How do I implement IActivationForViewFetcher for a child UserControl? - winforms

I've just added ReactiveUI to an existing code base. Of course, for the first control I tried it with I hit a snag. I'm using it with a UserControl embedded in a TabControl. The code looks something like this:
public partial class TabPageControl : UserControl, IViewFor<TestViewModel>
{
public TabPageControl()
{
InitializeComponent();
ViewModel = new TestViewModel();
this.WhenActivated(dispose =>
{
dispose(this.Bind( ... ));
dispose(this.BindCommand( ... ));
});
}
}
When I run the app, I get the following error message:
Don't know how to detect when TabPageControl
is activated/deactivated, you may need to implement
IActivationForViewFetcher
So, how do I implement IActivationForViewFetcher? I'm not sure what I'm supposed to do with GetAffinityForView. I'm assuming in GetActivationForView I need to check to see if the UserControl is the currently visible inside the TabControl?

Although I would like to understand how to implement the methods for IActivationForViewFetcher (especially the part where I identify that a control is in the VisualTree) - the real cause of my problem was that my main assembly didn't have the appropriate references (the controls are in a class assembly).
I'm assuming (because I've skimmed the ReactiveUI source) ReactiveUI.Winforms.Registrations needs to be instantiated by the main assembly - which includes registering ActivationForViewFetcher.
Incidentally, the class library is written in C# and the main assembly is VB.NET. So I'm not sure whether this contributed to the problem.
At least it's working now!

I don't if this will ever help anybody, since this thread is so old.
What solved my issue was having ReactiveUI.WPF,ReactiveUI.WinForms, CefSharp.WPF and CefSharp.WinForms NuGet references on all the projects/plugins that were running on the App.
My suspicion is that when ReactiveUI/CefSharp is initialized and it doesn't contain all the info/files it needs, it will not possible to add them later on runtime. But this is just guessing based on my experience.

I know it's an old thread, but just to save other developers time when facing this problem.
My solution was to add the following code in the entrypoint of the project that makes use of ReactiveUi and ReactiveUi.Wpf.
var reactiveUiWpfName = typeof(ReactiveUI.Wpf.Registrations).Assembly.FullName;
Assembly.Load(reactiveUiWpfName);
Of course, it was just required because I couldn't reference ReactiveUi or ReactiveUi.Wpf in my application startup project due to the project specifications, otherwise this error wouldn't appear anyway.
(Please, observe that, in your case you should use ReactiveUi.Winforms in the places I've used ReactiveUi.Wpf)

Related

Instantiating a new type with MEF

I am using CompositionInitializer.SatisfyImports(this) from Glen Block with a WPF application using Prism 4.1 and Prism's MEFExtensions.
I have used this many times before and not had a problem, but every once in a while when I call SatisfyImports(this) and get the following error:
A first chance exception of type
'System.Resources.MissingManifestResourceException' occurred in
mscorlib.dll
Additional information: Could not find any resources appropriate for the specified culture or the neutral culture. Make sure
"System.ComponentModel.Composition.Initialization.Strings.resources"
was correctly embedded or linked into assembly
"Microsoft.ComponentModel.Composition.Initialization.Desktop" at
compile time, or that all the satellite assemblies required are
loadable and fully signed.
If there is a handler for this exception, the program may be safely continued.
Anyone know why I'm getting this error and how to fix it?
The CompositionInitializer approach doesn't work with WPF in some cases, as evidenced by the MissingManifestResourceException above- basically, I think this is saying that one of the imports is failing due to some resource problem of the imported DLL... which you may or may not have any control over.
The better approach (I think) is to use the MEF ExportFactory to instantiate objects for WPF applications rather than the CompositionInitializer:
[Export]
public class OrderController {
[Import]
public ExportFactory<OrderViewModel> OrderVMFactory {get;set;}
public OrderViewModel CreateOrder() {
return OrderVMFactory.CreateExport().Value;
}
}
Worked for me anyways.
I do have some questions about memory management and the export factory, but that's another post :)

Ninject for winforms - does my architecture make this useless?

I'm trying out Ninject with a winforms app (basically a sketch, I'm using it sort of like a kata, but nothing so rigorous or specific) in .net 4.
To create the main form, I'm doing something like:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
[...]
IKernel kernel = BuildKernel();
Application.Run(kernel.Get<frmMain>());
}
static IKernel BuildKernel()
{
var modules = new INinjectModule[]
{
[..modules]
};
return new StandardKernel(modules);
}
}
Fine. This creates a main form and displays it nicely, passing the appropriate interface implementations to the injected constructor.
Now what? My application is an MDI and will have several child windows for manipulating the application model. I don't have a reference to the kernel anymore, so how am I supposed to Get() these forms? The obvious answer is 'pass the kernel to the form' I suppose, but that's a horribly messy strategy and I'm sure that doesn't fit into the philosophy of DI.
I will point out here that the documentation for Ninject 2 sucks. Everything I can find repeats the basic examples, without really explaining how DI using Ninject makes anything easier. The standard of example given isn't complicated enough to make the trouble of coding and creating modules and bindings worthwhile.
edit #1:
Having studied the links kindly provided by Sam Holder, I'm trying out the 'composition root' approach. My architecture now forces all the Forms it uses to derive from a CompositedForm with constructor semantics thus:
[Inject]
public CompositingForm(ICompositionRoot CompositionRoot)
{
InitializeComponent();
this.CompositionRoot = CompositionRoot;
}
public readonly ICompositionRoot CompositionRoot;
public CompositingForm() : this(new DummyCompositionRoot()) { }
The second constructor is for the benefit of the Forms Designer, which is stupid and can't understand the form markup unless you provide an empty constructor. Now, every form created using IKernel.Get<AForm>() will (should) have a composition root injected into it.
So, as I am a slow learner - now the question is really 'What should go in this composition root'?
can't you pass a factory for creating the child forms to the forms constructor, and the form uses this to get them, then ninject will wire up the factory dependency when the form is created using the get?
I think you should configure everything in the application root using the DI container and after that the container shouldn't be needed, but I've not really used DI containers in anger, and not NInject at all, so am going on what I've read...
This answer may help
Note: I do not know much about Ninject but i worked with Spring.net that is much more complicated. The principles behind sould be something similar.
Sam Holder answer is excellent if you have several objects of one (injected) type to create (for example CustomerOrderItem).
If you just want to wire your mainform i would sugest that your mdi-frmMain constructor gets parameters for every childwindow it should contain and let Ninject create and insert the childwindows. This way there is no need to Reference NInject outside "class Program
". This is called Constructor-Injection.
Alternatively you can add a method to the form that adds a page to you mdi (MethodInjection).
static void Main()
{
[...]
IKernel kernel = BuildKernel();
var main = kernel.Get<frmMain>();
main.AddClientForm(kernel.Get<CustomerForm>()) ;
main.AddClientForm(kernel.Get<InvoiceForm>()) ;
Application.Run(main);
}
Thanks to João Almeida and Kellabyte I have found a method that is more or less satisfactory:
Define a custom Attribute which exposes whatever business rules you care about;
Define an implementation of IInjectionHeuristic which recognises this attribute;
Use a ViewModelLocator to load modules into the ninject kernel.

Using Moq at Blend design time

This might be a bit out there, but suppose I want to use Moq in a ViewModel to create some design time data, like so:
public class SomeViewModel
{
public SomeViewModel(ISomeDependency dependency)
{
if (IsInDesignMode)
{
var mock = new Mock<ISomeDependency>();
dependency = mock.Object; // this throws!
}
}
}
The mock could be set up to do some stuff, but you get the idea.
My problem is that at design-time in Blend, this code throws an InvalidCastException, with the message along the lines of "Unable to cast object of type 'Castle.Proxies.ISomeDependencyProxy2b3a8f3188284ff0b1129bdf3d50d3fc' to type 'ISomeDependency'." While this doesn't necessarily look to be Moq related but Castle related, I hope the Moq example helps ;)
Any idea why that is?
Thanks!
I'm having a similar issue, except that the cast is coming from a dynamically generated assembly (Blend_RuntimeGeneratedTypesAssembly) type that is masquerading as one of my types.
For no apparent reason.
Which is driving me CRAZY.
I used to think that I needed to do this sort of trick but after much experiementing and searching about, discovered that Blend 4 now can create design time sample datacontexts based on an existing class.
This effectively gives you a dummy class that looks just like your VM class so that you can add your binding etc.
It works well enough that this is the technique we now recommend.
A possible disadvantage with this is that if you need your real VM to perform some sort of interactivity then the proxy of course can't do that - you'd have to manually change values, or swap to another design time object. But in practice, I've rarely encountered this scenario. Most of the time, you set the state of the VM and then take ages getting the look right.
Update: released on github: https://github.com/GeniusCode/GeniusCode.Components.DynamicDuck
I also ran into a similar problem when trying to use castle to mock viewmodels at design time. We wrote our own msil duck / mock library, and it works well for that purpose.
I blogged about it here: http://blogs.geniuscode.net/JeremiahRedekop/?p=255
We are working to release the library under MS-PL and deploy on GitHub.

"The DOM/scripting bridge is disabled" error in Blend

I've been given a custom Silverlight control to use, and everytime I open it up in Blend, get the "The DOM/scripting bridge is disabled" error.
Looking in the control's source code, I can see calls to
public override void OnApplyTemplate()
{
...
HtmlPage.Window.Invoke("GetPrimaryGradStart").ToString()
which I'm guessing might be the problem. Any ideas about what I can do, or am I back to pure XAML?
cheers
Toby
usually (i.e. when a Silverlight app is embedded in an HTML page) one has to set the "enablehtmlaccess" parameter to true for the app via HTML or JavaScript, because otherwise calls like HtmlPage.Window.Invoke are not allowed (and throw an exception).
So I guess the problem is that blend does/can not set that parameter and only shows that message instead.
If you have control over the code, you could add a condition that checks whether you are in design mode or runtime mode using DesignerProperties.IsInDesignTool, for example:
if (!DesignerProperties.IsInDesignTool)
{
// Do the "evil stuff"
HtmlPage.Window.Invoke("GetPrimaryGradStart");
}
Hope that helps.
Cheers, Alex
EDIT: If it does help, you might also want to add some pre-compiler directives to your code so that you won't have those design tool stuff statements in your production app:
#if !RELEASE
if (!DesignerProperties.IsInDesignTool)
#endif
HtmlPage.Window.Invoke("GetPrimaryGradStart");

How can I loosely reference modules in Prism so they can or cannot exist?

In this stackoverflow question I learned that Prism/Unity is not as decoupled as I thought, e.g. if I have this class which gets menuManager injected into its constructor, then I have to make sure that this class actually exists somewhere (I thought that you could just pull the .dll that contains the class and the container would deal with it, e.g. injecting a null in its place):
public class EmployeesPresenter
{
public EmployeesPresenter(IMenuManager menuManager)
{
}
}
But I can deal with that: the application cannot run without a MenuModule (or else as was suggested I could have a NullMenuModule which does nothing but keeps the application from breaking).
However, the application I am building will have a MenuManager class in the MenuModule and every module will have to register everything it wants to have in the menu with the MenuManager. However, I want to be able to swap out MenuModules e.g. have a InfragisticsMenuModule and have a TelerikMenuModule, etc.
However, when I am in e.g. the CustomersModule, in order to use TelerikMenuModule, I need to reference it. And when I want to use InfragisticsMenuModule, I need to reference that.
So how will I be able to "hot swap" TelerikMenuModule with InfragisticsMenuModule without recompiling all my modules with new references, e.g. I want to replace this:
Application.exe
Customers.dll
TelerikMenuModule.dll
with this:
Application.exe
Customers.dll
InfragisticsMenuModule.dll
and simply be able to restart the application and it runs with the new InfragisticsMenuModule.dll and does not complain that TelerikMenuModule.dll no longer exists.
This is where interfaces come in. You need something like:
public interface IMenuSystem
{
// whatever operations need to be offered by a menu system
}
Application.exe and Customers.dll may only refer to that interface. They aren't allow to know about a specific implementation.
Then you would use configuration steps (calling Register... methods or using a config file) to specify which type will provide the implementation of MenuSystem.
For obvious reason MEF comes to mind here and is designed for stuffs like this. I haven't had a chance to use Unity, so I'm not sure if it has something built in like this (i.e. scanning a directory for an IMenuModule implementation), but MEF can do this.
Suggestion also is to put this IMenuModule in a common assembly (separate from your other assembly). I usually called this thing Something.Core.dll.
So you might have: Application.exe, Customer.dll, Application.Core.dll, and your specific MenuModule implementation.
Your specific MenuModule implementation will reference the Application.Core assembly to gain access to its IMenuModule interface and implement it there.

Resources