We're implementing our own cross platform framework using the binding capabilities of MvvmCross Core.
My question is how can custom bindings be registered within Mvx without the setup.
Custom binding used is an imeActionBinding similar to:
https://gist.github.com/slodge/8270923
attempted registration using:
Mvx.CallbackWhenRegistered<IMvxTargetBindingFactoryRegistry>(RegisterCustomBindings);
protected virtual void RegisterCustomBindings(IMvxTargetBindingFactoryRegistry registry)
{
EditTextImeActionBinding.Register(registry);
}
Tried the same thing with project ChimpLight in the LightSetup:
Mvx.RegisterSingleton<IMvxTargetBindingFactoryRegistry>(new MvxTargetBindingFactoryRegistry());
var customBindingRegistry = Mvx.Resolve<IMvxTargetBindingFactoryRegistry>();
EditTextImeActionBinding.Register(customBindingRegistry);
xaml:
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="Search"
android:inputType="text"
android:imeOptions="actionSearch"
local:MvxBind="Text LastName;ImeAction ResetCommand" />
no exceptions - but it seems the custom binding never gets loaded :|
what am I missing?
Thanks to Stuart for the simple answer: use the existing binding.
Using the N-30 Chimplight example code, the only added code to LightSetup class is:
Mvx.CallbackWhenRegistered<IMvxTargetBindingFactoryRegistry>(registry =>
{
EditTextImeActionBinding.Register(registry);
});
Related
I'm working at a middleware for aspnetcore2.0 where I want to execute some razor view.
Actually I need a error handling middleware which would show nice pages from razor views. I know that it's possible to do with UseStatusCodePagesWithReExecute based on status codes. But I need a more general approach - handle an exception in my middleware to delegate (in some cases) it to an error view.
I realized that DeveloperExceptionPageMiddleware does something similar to what I need. But I can't understand how it works even after digging into its sources.
Here is the place where that middleware returns a view - https://github.com/aspnet/Diagnostics/blob/dev/src/Microsoft.AspNetCore.Diagnostics/DeveloperExceptionPage/DeveloperExceptionPageMiddleware.cs#L206
But I can't understand what kind of view it is. It's nor a razor page (as it has no #page directive) neither an mvc view (but i'm not sure).
In the project there're two files for that view: ErrorPage.cshtml and ErrorPage.Designer.cs. How that Designer.cs was created? It looks like a generated file. But thanks to it there's a normal class in the project (ErrorPage) which can be used explicitly. It inherits Microsoft.Extensions.RazorViews.BaseView class from Microsoft.Extensions.RazorViews.Sources package.
So the middleware just execute that view:
var errorPage = new ErrorPage(model);
return errorPage.ExecuteAsync(context);
How can it be achieved in my project?
UPDATE [2018.06]: Please note that the post was written for .NET Core 2.0 times, there're breaking changes for RazorEngine in .NET Core 2.1.
It turned out that it's pretty easy to do.
Aspnet prjoect has an internal tool called RazorPageGenerator (see https://github.com/aspnet/Razor/tree/dev/src/RazorPageGenerator) which can be used to compile views. After compilation with this tool we'll get normal classes which can be used in middlewares.
But before we need to get RazorPageGenerator and slightly customize it.
1.Create a new console project
dotnet new console -o MyRazorGenerator
2.put NuGet.config inside this folder
<configuration>
<config>
<add key="globalPackagesFolder" value="./packages" />
</config>
<packageSources>
<add key="aspnetcore-dev" value="https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json " />
</packageSources>
</configuration>
3.Add the following in csprj (as dotnet add package doesn't support installing pre-prelease packages)
<ItemGroup>
<PackageReference Include="RazorPageGenerator" Version="2.1.0-*" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.Extensions" Version="2.1.0-*" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Language" Version="2.1.0-*" />
</ItemGroup>
4.restore dotnet restore to check you got RazorPageGenerator
5.add into Program.cs:
public static int Main(string[] args)
{
if (args == null || args.Length < 1)
{
Console.WriteLine("Invalid argument(s).");
return 1;
}
var rootNamespace = args[0];
var targetProjectDirectory = args.Length > 1 ? args[1] : Directory.GetCurrentDirectory();
var razorEngine = RazorPageGenerator.Program.CreateRazorEngine(rootNamespace, builder => {
FunctionsDirective.Register(builder);
InheritsDirective.Register(builder);
SectionDirective.Register(builder);
});
var results = RazorPageGenerator.Program.MainCore(razorEngine, targetProjectDirectory);
foreach (var result in results)
{
File.WriteAllText(result.FilePath, result.GeneratedCode);
}
Console.WriteLine();
Console.WriteLine($"{results.Count} files successfully generated.");
Console.WriteLine();
return 0;
}
6.Now we have our own generator and can compile views
7.Create a Razor View (.cshtml)
8.run our generator to compile view:
dotnet run --project .\MyRazorPageGenerator\MyRazorPageGenerator.csproj Croc.XFW3.Web .\Middleware
here I assume that the view is inside Middleware\Views folder.
9.Generator creates a file like ErrorPage.Designer.cs (if view was ErrorPage.cshtml) which we can use:
public async Task Invoke(HttpContext context)
{
try
{
await _next.Invoke(context);
if (context.Response.StatusCode == StatusCodes.Status404NotFound)
{
var statusCodeFeature = context.Features.Get<IStatusCodePagesFeature>();
if (statusCodeFeature == null || !statusCodeFeature.Enabled)
{
if (!context.Response.HasStarted)
{
var view = new ErrorPage(new ErrorPageModel());
await view.ExecuteAsync(context);
}
}
}
}
}
Here we're returning our view in case of 404 error and absense of StatusCodePagesMiddleware. Can be useful for embedded UI in libs.
The generated code uses staff which should be added into your project. To get it we need to acquire nuget package Microsoft.Extensions.RazorViews.Sources. Again it’s not on nuget.org so we need to install it from https://dotnet.myget.org/feed/aspnetcore-dev/package/nuget/Microsoft.Extensions.RazorViews.Sources.
This might be a very simple Spring EL question. I have defined a new end-state in cas login-flow as follows:
https://myhost:8443/mymodule/somepage" />
We need to use a URL defined in cas.properties instead of hard coding the URL in externalRedirect new name. Is it possible to use something
and define myurl in cas.properties.
We are usign CAS 3.5.2
I've struggled the same problem, but found a much nicer solution.
<view-state id="orderExternalView" view="externalRedirect:#{propertyConfigurer.getProperty('link.externalOrderView')}" />
Maybe this isn't the solution that you are looking for, but I made it work with a bean defined in cas-servlet.xml.
<bean id="loadUrls" class="yourpackage.LoadUrls" c:url="${cas.property.myUrl}"/>
Then, in the LoadUrls class I have the following code:
public class LoadUrls{
private String url;
public LoadUrls(String url) {
this.url= url;
}
public void loadUrlsFromWebflow(RequestContext context) {
// [I used flowScope, you can use any other if you want]
context.getFlowScope().put("urlWebflow", this.url);
}
}
The last thing you need is to invoke this method from the webflow:
<action-state id="stateLoadUrl">
<evaluate expression="loadUrls.loadUrlsFromWebflow(flowRequestContext)"/>
<transition to="redirectAction"/>
</action-state>
<end-state id="redirectAction" view="externalRedirect:#{flowScope.urlWebflow}"/>
This is just an idea, you can tweak it to fit your needs. An by the way, if you find the solution using just an EL Spring expression, let me know, because I need the same exact thing!
I have a GridView and the IsItemClickEnabled is set to true. In this case, the ItemClick event is fired, and it calls a delegate with a sender and an ItemClickEventArgs. I'm using MVVM (Caliburn.Micro), and my view models are all sitting in a portable class library (PCL). All command routing, etc., is done by Reactive-UI. The View's data context is set to the view model, as you might expect.
The problem is ItemClickEventArgs is not available in a PCL configuration as far as I can tell. So I am currently at a loss as how to sink that event in my view model. Heck - even without using a reactive ui command.
Here is my grid view defined:
<GridView x:Name="PaperList" Margin="0" Grid.Column="1" IsItemClickEnabled="True" ItemClick="whatgoeshere?"/>
My simplest idea is to replace "whatgoeshere?" with a method in the view's code-behind, for example:
public void ForkItUp(object sender, ItemClickEventArgs args)
{
// How do I get this information back to the view model?
}
And of course, that works, that method gets called. But once I'm there, how the heck do I get the information back into my View Model? As far as I know the view knows nothing about the view model.
The only thing I can think of is I need to create some property that contains the PCL object that was clicked on. This method would stuff the item into that property, and through some magic of data-binding that would be sent back to the view model. If so, I have no idea how to participate in the data-binding process to get that right! Ack! :-)
I don't know if this makes a difference yet, but I'm not using universal apps! And I'm using a nasty hybrid of Caliburn.Micro to hook up my views, and Reactive-ui and rx to run all my commands. I don't like making anything easy!
Here's how I would do it
ReactiveCommand ItemClicked { get; protected set; }
public MyCoolViewModel()
{
ItemClicked = new ReactiveCommand();
}
// In My View
gridView.ItemClicked += (o,e) => ViewModel.ItemClicked.Execute(e.Item);
As far as I know the view knows nothing about the view model.
This isn't how MVVM works - the View can know all kinds of stuff about the ViewModel, that's the whole idea! However, the ViewModel can know nothing about any Views.
I found two different approaches worked, based on the answer that Paul gave. I ended up using the second. In the first approach I added a public method to my MyViewModel:
public void ClickOnTile(PaperTileViewModel pt)
{
code to run;
}
Then, in my View I added the following:
public void ForkItUp(object sender, ItemClickEventArgs args)
{
var obj = DataContext as MyViewModel;
obj.ClickOnTile(args.ClickedItem as PaperTileViewModel);
}
And the XAML for my view for the grid view:
<GridView x:Name="PaperList" Margin="0" Grid.Column="1" IsItemClickEnabled="True" ItemClick="ForkItUp"/>
I'm a C++ guy by training, so the lack of type safety got to me a bit and lead to this second solution (which is the one that I ended up committing). So I ended up doing the following in the end. I first created an interface in my ViewModel's PCL:
public interface IHomePageViewCallback
{
void FinalizeVMWiring(HomePageViewModel homePageViewModel);
}
Then, in the View I implemented the interface:
public sealed partial class MyPageView : Page, IHomePageViewCallback
{
public MyPageView()
{
this.InitializeComponent();
}
public void FinalizeVMWiring(MyViewModel myVM)
{
PaperList.ItemClick += (s, args) => myVM.NavigateToPaperTile.Execute((args.ClickedItem) as PaperTileViewModel);
}
}
where NavigateToPaperTile is a ReactiveCommand similar to what Paul has in his answer. This funny call back is needed because as far as I can tell there is no easy way to get a typed version of the ViewModel in Caliburn.Micro.
For completeness here is the XAML:
<GridView x:Name="PaperList" Margin="0" Grid.Column="1" IsItemClickEnabled="True"/>
I have written a custom JUnit runner that I want to become part of an eclipse plugin that will launch tests using this runner without having to apply the #RunWith annotation to the class. I have managed to get an additional item under the 'Run As' context menu, using the org.eclipse.debug.ui.launchShortcuts extension point. However, I am not sure how to invoke the test using my custom runner.
So I figured out a way to do what I wanted. However, it does seem a bit hacky. But, I thought that I would post the answer here in case someone else runs into the same problem.
First you have to register a junit kind like this:
<extension point="org.eclipse.jdt.junit.internal_testKinds">
<kind
id="my.junit.kind"
displayName="Your Kind Name"
finderClass="org.eclipse.jdt.internal.junit.launcher.JUnit4TestFinder"
loaderPluginId="org.eclipse.jdt.junit4.runtime"
loaderClass="your.test.loader.MyLoaderClass">
<runtimeClasspathEntry pluginId="org.eclipse.jdt.junit4.runtime" />
<runtimeClasspathEntry pluginId="org.eclipse.jdt.junit.core" />
<runtimeClasspathEntry pluginId="org.eclipse.jdt.junit.runtime"/>
</kind>
</extension>
In the xml you have to specify a custom implementation of org.eclipse.jdt.internal.junit.runner.ITestLoaderwhich in turn returns an implementation of org.eclipse.jdt.internal.junit.runner.ITestReference. The core part is the implementation of ITestReference, because this is where you create an instance of your custom JUnit runner.
public class MyTestReference extends JUnit4TestReference
{
public MyTestReference(final Class<?> p_clazz, String[] p_failureNames)
{
super(new Request()
{
#Override
public Runner getRunner()
{
return new MyCustomRunner(p_clazz);
}
}, p_failureNames);
}
...
}
Then finally you have to link this with a launch shortcut that sets the kind appropriately
public class MyJunitLaunchShortcut extends JUnitLaunchShortcut
{
#Override
protected ILaunchConfigurationWorkingCopy createLaunchConfiguration(IJavaElement p_element) throws CoreException
{
ILaunchConfigurationWorkingCopy config = super.createLaunchConfiguration(p_element);
config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_RUNNER_KIND, "my.junit.kind");
return config;
}
}
This does use a bunch of internal classes, so there is probably a better way. But this seems to work.
I have an application that uses DynamicProxy 3.1 to do runtime interception. I have a test assembly that uses NSubstitute for mocking. I just wrote some "integration" tests against my fully bootstrapped container (StructureMap using InterceptWith to do the interception) so that I can assert that certain types coming out of the container are proxied properly.
[Subject(typeof(RobotBoard))]
public class When_resolving_an_intercepted_type : WithContainer<IRobotBoard>
{
It should_have_recovery = () => Subject.ShouldHaveInterceptor<RecoveryInterceptor>();
}
public static class TestExtensions
{
public static void ShouldHaveInterceptor<T>(this object obj)
where T : IInterceptor
{
((IProxyTargetAccessor)obj)
.GetInterceptors()
.ToList()
.Exists(x => x is T)
.ShouldBeTrue();
}
}
However, I get this error, indicating that DynamicProxy references are inside the NSubstitute assembly, too! (it appears to be ilmerged).
Error 11 MyCompany.MyModule.Specifications D:\code\source\tests\When_resolving_an_intercepted_type.cs
The type 'Castle.DynamicProxy.IProxyTargetAccessor' exists in both 'd:\code\packages\Castle.Core.3.1.0\lib\net40-client\Castle.Core.dll' and 'd:\code\packages\NSubstitute.1.4.2.0\lib\NET40\NSubstitute.dll'
Is there anyway around this conflict?
You could grab the NSubstitute source code and remove the ilmerge commands from the project's targets. I've opened issue 86 on their repository to address this.
<exec command=""$(MSBuildProjectDirectory)\..\..\ThirdParty\Ilmerge\ILMerge.exe" /internalize:"$(MSBuildProjectDirectory)\ilmerge.exclude" /keyfile:$(AssemblyOriginatorKeyFile) /out:#(MainAssembly) "#(IntermediateAssembly)" #(AssembliesToMerge->'"%(FullPath)"', ' ')" Condition=" '$(TargetFrameworkVersion)' == 'v3.5'" />
<exec command=""$(MSBuildProjectDirectory)\..\..\ThirdParty\Ilmerge\ILMerge.exe" /internalize:"$(MSBuildProjectDirectory)\ilmerge.exclude" /keyfile:$(AssemblyOriginatorKeyFile) /out:#(MainAssembly) /targetplatform:"v4,$(FrameworkReferenceAssemblyPath)." "#(IntermediateAssembly)" #(AssembliesToMerge->'"%(FullPath)"', ' ')" Condition=" '$(TargetFrameworkVersion)' == 'v4.0'" />
You could try using an alias to reference the NSubstitute or DynamicProxy assemblies.
See MSDN How to: Use the Global Namespace Alias (C# Programming Guide) for more info.
You can use the 'extern alias' directive as explained here:
http://blogs.msdn.com/b/ansonh/archive/2006/09/27/774692.aspx
basically
(1) in VS, go to the assembly reference for FooVersion1, and right click > Properties.
(2) change 'aliases' value to 'FooVersion1'
(3) in your .cs file use:
extern alias FooVersion1;
using foo = FooVersion1::FooVersion1;
...
var something = foo.FooClass();