i'm using Prism-MEF-WPF and Sometimes i need view model gets constructed from the XAML
of the view, so the container is not involved and can’t do the dependency injection
automatically (as there is no Export attribute used with VM).so there should be some
class in Prism-WPF like CompositionInitializer to enable me to ask the container to
do the injection.In case there is equivalent class how to use it, and in case there is
no equivalent how to construct view model from xaml of the view knowing that i use MEF.
Thanks in advance.
The problem is that you can't create an object in XAML if it doesn't have a parameterless constructor.
Using the ServiceLocator, you can achieve this. It will work as an IoC (and is set up by Prism/MEF, you just have to drop the .dll):
The xaml:
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
The code-behind:
class ViewModel : NotificationObject
{
public ViewModel()
{
var firstDependency = ServiceLocator.Current.GetInstance<FirstDependencyType>();
//... more dependencies here instead of as constructor parameters
}
//class code omitted for brievity
}
Here is the right answer which i got from Agustin Adami "http://blogs.southworks.net/aadami":
Based on my understanding the view model can be instantiated in XAML as the view’s DataContext only if a view model does not have any constructor arguments. And as far as I know creating objects defined in XAML by partnering with an Inverse of Control Container is currently not supported.
Regarding the CompositionInitializer class, as far as I know there is no equivalent class for WPF, on the other hand regarding this topic, I believe you could find the following blog post interesting:
•http://reedcopsey.com/2010/03/26/mef-compositioninitializer-for-wpf/
Also, I believe an alternative for this could be registering the CompositionContainer class like mentioned in this thread:
http://compositewpf.codeplex.com/discussions/311933
As this could let you retrieve this class for example in your view model's constructor, in order to call the SatisfyImportsOnce method to satisfy the Imports defined in the passed class:
this.compositionContainer =ServiceLocator.Current.GetInstance();
this.compositionContainer.SatisfyImportsOnce(this);
Bootstrapper class is what you are looking for. It uses UnityContainer for injecting dependencies. This link here might be of your interest too..
EDIT
If i am getting right, you want to create a ViewModel from your xaml which can be achieved like this(Here local is namespace of your ViewModel class) -
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
Related
I'm using Caliburn.Micro (CM) in a WPF application with ViewModel-first approach. I'm composing the main view with a command bar and an active item. Main viewModel sets the property for the command bar viewModel, and navigates to active item correctly.
Everything looks fine at runtime, the issue is only related to design-time: the main view shows empty in designer and I cannot find how to set it correctly. I managed to having this working in other scenarios, e.g. when setting the datacontext at design time for a whole Window or UserControl, i.e. when that's the root UI element in XAML. But now I'm not able to to this for child ContentPresenter UI elements within a Window.
This is an excerpt of the main view I'm composing:
<Window x:Class="...MainView" ...>
<DockPanel ...>
<!-- this one binds to a property of type CommandBarViewModel -->
<ContentControl x:Name="CommandBar" ... />
<ContentControl x:Name="ActiveItem" ... />
</DockPanel>
</Window>
I've checked a number of related reads, but none of them seems to fit/solve my issue. This question is basically the same as mine, but has no answers. That has a reference to this other question which it seems to me is going for a View-first approach, judging by the cal:View.Model bindings.
I tried adding a design-time context like the following (fake namespace not shown for brevity):
<ContentControl x:Name="CommandBar" ...
d:DataContext="{d:DesignInstance Type=fake:DesignTimeCommandBarViewModel, IsDesignTimeCreatable=True}"
cal:Bind.AtDesignTime="True"/>
but then I incur in one of two cases:
if DesignTimeCommandBarViewModel inherits from the actual CommandBarViewModel, then I incur in somewhat the usual problem of design-time Vs dependency injection: the default constructor passes null for all injected dependencies, and base constructor or something else gives problem. I mean, it seems it would take some effort to find a workaround for this, and just for design-time support
if DesignTimeCommandBarViewModel does not inherit from the actual viewModel, then it seems that (correctly) the CommandBarView is not instantiated, as now there's no relationship anymore between the viewModel and that view.
Have you got any idea about this? Maybe this should be solved with a design-time version of the hosting MainViewModel?
Other references I checked: this answer, from Rob Eisenberg himself, this CM thread, this other SO
Edit
Following my last (auto-)hint, I'm trying also creating and instantiating a DesignTimeMainViewModel, not inheriting from MainViewModel, which exposes the same properties and sets a DesignTimeCommandBarViewModel in its default constructor. In this case, in place of the command bar the designer shows the classic CM complaint: cannot find view for the DesignTimeCommandBarViewModel.
What's next?
Well, here's the solution I found: I'd be glad to hear about better ways or other suggestions.
Host MainView XAML specifies a design-time data-context pointing to a design-time version of the Main view-model which, by the way, does not inherit from the runtime version MainViewModel. ContentControl items are left untouched.
<Window x:Class="...MainView" ...
d:DataContext="{d:DesignInstance Type=fake:DesignTimeMainPanelViewModel, IsDesignTimeCreatable=True}"
cal:Bind.AtDesignTime="True">
<DockPanel ...>
<ContentControl x:Name="CommandBar" ... />
<ContentControl x:Name="ActiveItem" ... />
</DockPanel>
</Window>
DesignTimeMainPanelViewModel has the same public properties as MainPanelViewModel, has a default c'tor without dependencies and its c'tor sets the CommandBar property to a new instance of DesignTimeCommandBarViewModel:
public class DesignTimeMainPanelViewModel
{
public DesignTimeMainPanelViewModel()
{
CommandBar = new DesignTimeCommandBarViewModel();
ActiveItem = ...some instance here as well...;
}
public DesignTimeCommandBarViewModel CommandBar { get; private set; }
public IScreen ActiveItem { get; private set; }
}
DesignTimeCommandBarViewModel class is decorated with a custom Attribute having only one required parameter, the System.Type of the view associated with that view-model.
During bootstrap the code adds a new ViewLocator strategy to get the view Type from the view-model Type, by setting a new ViewLocator.LocateTypeForModelType.
The new locator function will try to find a view Type if the standard locator function cannot find one. Granted, it will look for the custom attribute on view-model Type, and if found that would be the returned view Type. Here's the gist of that:
Type viewType = _previousLocate(viewModelType, displayLocation, context);
if (viewType == null)
{
FakeViewAttribute fakeViewAttr = Attribute.GetCustomAttribute(viewModelType, typeof(FakeViewAttribute)) as FakeViewAttribute;
if (fakeViewAttr != null) viewType = fakeViewAttr.ViewType;
}
return viewType;
I took a course on VB.Net + WPF at university last year. For the final project, I decided to give MVVM a go (we hadn't discussed it at all in the course, I had just researched it and thought it would be a useful exercise). It was a good experience however I'm rather sure I might have made some poor choices when it came to design.
I've since graduated and my job has nothing to do with WPF or Windows development however I'm developing a small application in my own time and thought it would be fun to use C# and WPF (C# is a language I very much like to work with and I enjoyed working with WPF so it's a pretty logical choice).
Anyway, I'm using this as an opportunity to learn more about MVVM and try and implement it in a better way than I did previously. I've done a bit more reading and am finding it a lot easier to graph than I had when trying to implement it alongside learning WPF.
I've used In The Box MVVM Training as a guide and will be using Unity for dependency injection at this.
Now, in the sample app developed in the guide, there is a single view model (MainWindowViewModel). The MainWindow is pretty much a container with 3 or 4 UserControls which all share the DataContext of the MainWindow.
In my app, I'd like to have a tab-based interface. As such, the MainWindow will be primary concerned with displaying a list of buttons to switch the current view (i.e. move from the 'add' view to the 'list view'). Each view will be a self-contained UserControl which will implement it's own DataContext.
The same code in the app is as follows:
MainWindow window = container.Resolve<MainWindow>();
window.DataContext = container.Resolve<MainWindowViewModel>();
window.Show();
That's fine for setting data context of the MainWindow, however how will I handle assigning each user context it's own ViewModel as a DataContext?
EDIT: To be more specific, when I say tab-based interface, I don't mean it in the sense of tabs in a text editor or web browser. Rather, each 'tab' is a different screen of the application - there is only a single active screen at a time.
Also, while Slauma's post was somewhat helpful, it didn't really explain how I'd go about injecting dependencies to those tabs. If the NewStatementView, for example, was required to output it's data, how would I inject an instance of a class that implements the 'IStatementWriter' interface?
EDIT: To simplify my question, I'm basically trying to figure out how to inject a dependency to a class without passing every dependency through the constructor. As a contrived example:
Class A has Class B.
Class B takes as a constructor paramater needs an implementation of Interface I1.
Class B uses Class C.
Class C takes as a constructor paramater needs an implementation of Interface I2.
How would I handle this scenario using DI (and Unity)? What I don't want to do is:
public class A(I1 i1, I2 i2) { .... }
I could register everything using Unity (i.e. create I2, then C, then I1 and B, and then finally insert these into A) but then I would have to instantiate everything when I want to use A even if I might not even need an instance of B (and what if I had a whole bunch of other classes in the same situation as B?).
MVVM has lots of benefits, but in my experience wiring up the view models and the views is one of the biggest complexities.
There are two main ways to do this:
1:
Wire the view models to the views.
In this scenario, the XAML for the MainWindow contains the child controls. In your case, some of these views would probably be hidden (because you are only showing one screen at a time).
The view models get wired to the views, usually in one of two ways:
In the code behind, after the InitializeComponents() call or in a this.Loaded event handler, let this.DataContext = container.Resolve<MyViewModelType>();
Note that in this case the container needs to be globally available. This is typical in applications that use Unity. You asked how children would resolve interfaces like IStatementWriter. If the container is global, the child view models could simply call container.Resolve<IStatementWriter>();
Another way to wire the view models into the views is to create an instance of the view model in XAML like this:
<UserControl ...>
<UserControl.DataContext>
<local:MyViewModelType/>
</UserControl.DataContext>
...
</UserControl>
This method is not compatible with Unity. There are a few MVVM frameworks that allow you to resolve types in XAML (I believe Caliburn does). These frameworks accomplish this through markup extensions.
2:
Wire the view up to the view model.
This is usually my preferred method, although it makes the XAML tree more complicated. This method works very well when you need to perform navigation in the main view model.
Create the child view model objects in the main view model.
public class MainViewModel
{
public MyViewModelType Model1 { get; private set; }
public ViewModelType2 Model2 { get; private set; }
public ViewModelType3 Model3 { get; private set; }
public MainViewModel()
{
// This allows us to use Unity to resolve the view models!
// We can use a global container or pass it into the constructor of the main view model
// The dependencies for the child view models could then be resolved in their
// constructors if you don't want to make the container global.
Model1 = container.Resolve<MyViewModelType>();
Model2 = container.Resolve<ViewModelType2>();
Model3 = container.Resolve<ViewModelType3>();
CurrentViewModel = Model1;
}
// You will need to fire property changed notifications here!
public object CurrentViewModel { get; set; }
}
In the main view, create one or more content controls and set the content(s) to the view models that you want to display.
<Window ...>
...
<ContentControl Content="{Binding CurrentViewModel}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:MyViewModelType}">
<local:MyViewType/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ViewModelType2}">
<local:ViewType2/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ViewModelType3}">
<local:ViewType3/>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
...
</Window>
Notice that we tie the child views to the view models through data templates on the ContentControl. These data templates could have been defined at the Window level or even the Application level, but I like to put them in context so that it's easier to see how the views are getting tied to the view models. If we only had one type of view model for each ContentControl, we could have used the ContentTemplate property instead of using resources.
EDIT: In this method, the view models can be resolved using dependency injection, but the views are resolved through WPF's resource resolution mechanism. This is how it works:
When the content for a ContentPresenter (an underlying component in the ContentControl) is set to an object that is NOT a visual (not derived from the Visual class), WPF looks for a data template to display the object. First it uses any explicit data templates set on the host control (like the ContentTemplate property on the ContentControl). Next it searches up the logical tree, examining the resources of each item in the tree for a DataTemplate with the resource key {x:Type local:OBJECT_TYPE}, where OBJECT_TYPE is the data type of the content. Note that in this case, it finds the data templates that we defined locally. When a style, control template, or data template is defined with a target type but not a named key, the type becomes the key. The Window and Application are in the logical tree, so resources/templates defined here would also be found and resolved if they were not located in the resources of the host control.
One final comment. If a data template is not found, WPF calls ToString() on the content object and uses the result as the visual content. If ToString() is not overridden in some meaningful way, the result is a TextBlock containing the content type.
<--
When you update the CurrentViewModel property on the MainViewModel, the content and view in the main view will change automatically as long as you fire the property changed notification on the main view model.
Let me know if I missed something or you need more info.
For a Tab-based interface this classical article about MVVM pattern in WPF might be very useful. (It also offers a downloadable sample application.)
The basic idea to connect each tab with a UserControl is as follows (only a rough sketch, details are in the article):
The MainWindow View has a ContentControl ...
<ContentControl Content="{Binding Path=Workspaces}"
ContentTemplate="{StaticResource WorkspacesTemplate}" />
... which binds to a collection of "Workspaces" in the MainWindowViewModel:
public ObservableCollection<WorkspaceViewModel> Workspaces { get; private set; }
This WorkspaceViewModel serves as a base class for all ViewModels you want to display as a tab.
The WorkspacesTemplate is a DataTemplate which binds a TabControl to the collection of WorkspaceViewModels:
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}" />
</TabControl>
</DataTemplate>
And for every specific Tab you have a UserControl with a ViewModel which derives from WorkspaceViewModel ...
public class MySpecialViewModel : WorkspaceViewModel
... and which is related to the UserControl by a DataTemplate:
<DataTemplate DataType="{x:Type vm:MySpecialViewModel}" >
<v:MySpecialUserControl />
</DataTemplate>
Now, if you want to open a tab you would have a Command in the MainWindowViewModel which creates the ViewModel belonging to that tab and add it to the Workspaces collection of the MainWindowViewModel:
void CreateMySpecialViewModel()
{
MySpecialViewModel workspace = new MySpecialViewModel();
Workspaces.Add(workspace);
}
The rest is done by the WPF binding engine. The TabControl recognizes automatically that this special workspace item in the collection is of type MySpecialViewModel and selects the right View/UserControl through the DataTemplate we have defined to connect ViewModel and View and displays it in a new Tab.
At the point where you resolve your Views deriving from UserControl, use property injection to resolve a new ViewModel for each one and set the DataContext property of the view to it.
I'm just getting started with the MVVM pattern in WPF and I decided that the most elegant way to structure my code was injecting the view-model in to the view's constructor.
This is all well and good, but ReSharper gives a warning in the XAML that my view doesn't have a default constructor. I'm assuming that this is so that I can construct my view in XAML if required, but that's only a guess.
What am I giving up by requiring my view to take a view-model in the constructor?
Edit: My view constructor looks like this:
public ExampleView(ExampleViewModel viewModel)
{
if (viewModel == null) throw new ArgumentNullException("viewModel");
DataContext = viewModel;
}
Answer: I settled on the following set up, where the DesignTime namespace contains mocked up versions of the ViewModel for testing and design time support.
ExampleView.xaml.cs
public ExampleView()
{
InitializeComponent();
}
public ExampleView(IExampleViewModel viewModel)
: this()
{
DataContext = viewModel;
}
ExampleView.xaml
<UserControl
x:Class="Wpf.Examples.ExampleView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:DesignTime="clr-namespace:Wpf.Examples.DesignTime">
<UserControl.DataContext>
<DesignTime:ExampleViewModel/>
</UserControl.DataContext>
</UserControl>
As you correctly recognized, requiring a non-default constructor will deny you using that control from XAML. That also means no more design-support and your designers will probably hate you. Finally you break all sorts of nice data binding scenarios. Like using the control as an ItemTemplate.
As a remedy for the missing design support, I would suggest implementing a default constructor which creates a mocked view-model which doesn't need any infrastructure. That way you can support design mode very elegantly and putting the view in a XAML file (e.g. for testing) will do something sensible.
As a remedy for the missing data binding support, you should ponder whether it might be better to consume the view model via the DataContext of your WPF control. This is common in WPF and---as far as I can tell---the intended way to pass the model to the view in WPF.
Assuming that you don't need designer support then I see no reasons.
To keep designer support you need a default constructor. When you define your own constructor you basically loose the autogenerated default constructor. Just create an explicit default constructor and you should be fine.
I have problem with base classes in WPF. I try to make a base class with some base elements, so that other windows can inherit these components. But all that i have, when I inherit base class is only empty window, without these elements. For better understanding i put my code here:
using XSoftArt.WPFengine;
namespace XSoftArt
{
public class WindowBase : Window
{
public WindowBase()
{
}
}
Code of the Windows, whitch inherits WindowBase:
namespace XSoftArt.WPFengine
{
public partial class NewAbility : WindowBase
{
public NewAbility()
{
base.ChildForm = this; InitializeComponent();
}
}
}
Or maybe someone can put an working example or link with implemented base classes in wpf?
Thanks
I don't think you really need to do what you are doing, but it is feasible. I think you are just forgetting to call the base class constructor.
using XSoftArt.WPFengine;
namespace XSoftArt
{
public class WindowBase : Window
{
//call base ctor
public WindowBase() : base()
{
}
}
}
You'll need to do this from your inherited classes as well:
namespace XSoftArt.WPFengine
{
public partial class NewAbility : WindowBase
{
public NewAbility() : base()
{
base.ChildForm = this; InitializeComponent();
}
}
}
And if you also have a XAML-defined view, you'll need to make sure your view is a WindowBase. To do this, change this:
<Window x:Class="MyApp.MyView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
...
>
<Grid>
</Grid>
</Window>
To this:
<local:WindowBase x:Class="MyApp.MyView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:XSoftArt;"
...
>
<Grid>
</Grid>
</local:WindowBase>
If you look at this class in Reflector you will see that the constructor calls the Window class's own "Initialize()" method, which sets a lot of things in motion. Specifically it appears to hook itself up to the Dispatcher, which is the work queue for all UI events.
In particular, you want to ensure that the InitializeComponent() method of the base class is called - this is the function that creates the controls that you defined in XAML.
Making a derived class is great if you want to inherit both controls and behaviour, but consider using Templates for a more flexible way of managing a common set of controls.
I don't think I'd ever use inheritance in WPF the way you're trying to use it.
I'll try and take a stab at answering your question. If I'm understanding you correctly, you're trying something like this:
You're creating a window that has both a XAML file and a code-behind.
You're adding "base elements" to the XAML for your window... I'm not sure what you mean by "base element", but I'm going to assume you mean you're adding UI elements to your window.
You're creating another window that "derives" from your first window in the code-behind, and the problem is that you're not seeing the UI elements on it from your "base" window.
If that is what you want to accomplish with WPF, I'd personally recommend against it, just because I'm personally not a fan of inheritance and have seen firsthand the dangers of letting inheritance get out of hand.
What you could try instead is organize your "base" UI elements into WPF UserControls. This tutorial might be able to guide you in the right direction. Good luck!
How do you pass "this" to the constructor for ObjectDataProvider in XAML.
Lets say my presenter class is:
public class ApplicationPresenter(IView view){}
and that my UserControl implements IView.
What do I pass to the ConstructorParameters in the code below so that the UserControl can create the ApplicationPresenter using the default constructor?
<ObjectDataProvider x:Key="ApplicationPresenterDS"
ObjectType="{x:Type Fenix_Presenters:ApplicationPresenter}"
ConstructorParameters="{ ?? what goes here ??}" d:IsDataSource="True" />
I only need to do this so that I can use Blend 2. I know that I can do this in the code behind, but if I do I can't instantiate the class from within Blend. I also know that I can create a parameterless constructor for ApplicationPresenter and pass it a dummy class that implements IView, but I would rather do this in markup if at all possible.
My code behind at the moment is:
public MyUserControl()
{
InitializeComponent();
DataContext = new ApplicationPresenter(this);
}
I'm just starting with Wpf and was under the misapprehension that I should be trying to do everything in XAML. I've just watched a few videos from WindowsClient.net which are starting to clear some things up. But boy is this a complex technology!!!
i don't know if it works, but you could give your user control a name , e.g.
x:Name="myUserCotrol"
and then use it in a binding:
... ConstructorParameters="{Binding ElementName=myUserControl}" ...
this could work
This will be directly supported (if memory serves well) in the next version of XAML as demonstrated by Rob Relyea at this year's PDC.