I have the below DataTemplate:
<DataTemplate DataType="{x:Type vm:MyViewModel}">
<views:MyView/>
</DataTemplate>
The thing is, my view model has a constructor that takes parameters which are automatically injected by the container (unity). In order for the DataTemplate to work though, MyViewModel needs to have a paramaterless constructor.
Is there any other way I can inject the appropriate values into my view model if I am using a DataTemplate to create it?
I don't think Views should be creating ViewModels.
ViewModels should be creating other ViewModels, and the View simply defines how to draw the ViewModel.
For example, a ParentViewModel might have a property called ChildViewModel. The ParentView will contain a ContentControl which has its Content bound to ChildViewModel, and a DataTemplate would be used to tell the application to draw ChildViewModel as a ChildView.
With that being said, how is your View currently creating your ViewModel? You could always add DependencyProperties to your View and build your ViewModel in the View's loaded event using these properties.
You might want to consider using an MVVM framework such as Caliburn.Micro, and take a ViewModel first approach.
Related
In an MVVM pattern, I have a single common ViewModel used by 3 usercontrols. I was instantiating the ViewModel and passing it as a parameter to the constructors of the user controls but this breaks XAML which requires that objects are constructed with parameterless constuctors.
What is the accepted best practise for creating a shared ViewModel?
You could create a ViewModel for your MainWindow which contains a property of Type SharedViewModel: public SharedViewModel SharedViewModel {get;set;}. You set the DataContext of your Window to your MainViewModel and bind to the shared ViewModel like:
<Window>
<Grid>
<UserControl1 DataContext="{Binding Path=SharedViewModel}"/>
<UserControl2 DataContext="{Binding Path=SharedViewModel}"/>
<UserControl3 DataContext="{Binding Path=SharedViewModel}"/>
</Grid>
</Window>
You can just add parameterless constructors for your UserControls
public MyUserControl() : base(new MyViewModel())
{}
public MyUserControl(MyViewModel viewModel)
{}
Note: This may break several design paradigms. :)
Dependency Injection with Unity ( http://msdn.microsoft.com/en-us/library/ff660899(v=pandp.20).aspx ) or MEF are the standard MVVM ways of coupling views to viewmodels
But don't forget that MVVM is a pattern, not a rigid framework. You can have a one-line hookup in the view's code behind:
InitializeComponent();
this.DataContext = new ViewModel(whatever);
without the sky falling.
You can have a base view that'll initialize the viewmodel
This is a question that extends from the originally posted here:
Link to loading-xaml through runtime
I'm working on a WPF MVVM application that loads XAML content dynamically from an external source, very similar as the answer in the post above.
Here is what I got so far:
My View declares an instance of the ViewModel as a resource and creates an instance of that ViewModel
In my ViewModel constructor I'm loading a XamlString property coming from an external source (file or db..)
In my view I have a button that user clicks after ViewModel finishes loading and in the click-event code-behind I'm deserializing the dynamically loaded XAML and add it to my grid.
My question is, how can I eliminate code-behind and automate the logic so the View can render the new xaml section dynamically right after the ViewModel is done getting the XAML content and initializing the string property?
Should I use some kind of Messaging Bus so the ViewModel notifies once the property has been set so the View can add the new content?
What troubles me is the fact that ViewModels do have a reference to Views and should not be in charge of generating UI elements.
Thanks in advance!
Edit:
Just to clarify: in my particular case I am not trying to bind a Business Object or Collection (Model) to a UI element (e.g. Grid) which obviously could be accomplished through templates and binding. My ViewModel is retrieving a whole XAML Form from an external source and setting it as a string property available to the View. My question is: Who should be in charge of deserializing this XAML string property into a UI element and add it programmatically to the my grid once my Xaml string property in the VM is set?
This sounds to me more of like a View responsibility, not ViewModel. But the pattern as i understand it enforces to replace any code-behind logic with V-VM bindings.
I have a working solution now and I'd like to share it. Unfortunately I did not get rid of code-behind completely but it works as I expect it to. Here is how it works(simplified):
I have my simplified ViewModel:
public class MyViewModel : ViewModelBase
{
//This property implements INPC and triggers notification on Set
public string XamlViewData {get;set;}
public ViewModel()
{
GetXamlFormData();
}
//Gets the XAML Form from an external source (e.g. Database, File System)
public void GetXamlFormData()
{
//Set the Xaml String property
XamlViewData = //Logic to get XAML string from external source
}
}
Now my View:
<UserControl.Resources>
<ViewModel:MyViewModel x:Key="Model"></ViewModel:MyViewModel>
</UserControl.Resources>
<Grid DataContext="{StaticResource Model}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel>
<!-- This is the Grid used as a Place Holder to populate the dynamic content!-->
<Grid x:Name="content" Grid.Row="1" Margin="2"/>
<!-- Then create a Hidden TextBlock bound to my XamlString property. Right after binding happens I will trigger an event handled in the code-behind -->
<TextBlock Name="tb_XamlString" Text="{Binding Path=XamlViewData, Mode=TwoWay, UpdateSourceTrigger=LostFocus, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" Visibility="Hidden" Loaded="tb_XamlString_Loaded" />
</StackPanel>
</Grid>
Basically I created a hidden TextBlock bound to my XAML String property in the ViewModel and I hooked its Loaded event to an event handler in the code behind of the View:
private void tb_XamlString_Loaded(object sender, RoutedEventArgs routedEventArgs)
{
//First get the ViewModel from DataContext
MyViewModel vm = content.DataContext as MyViewModel;
FrameworkElement rootObject = XamlReader.Parse(vm.XamlViewData) as FrameworkElement;
//Add the XAML portion to the Grid content to render the XAML form dynamically!
content.Children.Add(rootObject);
}
This may not be the most elegant but gets the job done. Like some people say, in MVVM there are some cases like this where little code-behind code is needed. It doesn't hurt and also part of this solution still uses the V-VM Binding principles when using the VM to retrieve and populate the XamlString property and exposing it to the View. If we would like to Unit Test the XAML parsing and loading functionality we could delegate it to a separate class.
I hope someone finds this useful!
I'm having trouble understanding what you're saying, so my answer will be based on my interpretation. You should consider posting a sample (simplified) of what you're trying to do.
1) I think you're misunderstanding what MVVM does. MVVM is mostly a binding-based pattern. Your view model should be exposing properties containing business objects and your view should just be binding to those properties. If I am misunderstanding you, and that's what you are doing, then your problem is that your view needs to be aware of when the properties get updated (after you deserialize your xaml, etc). There are two ways to do this: INotifyPropertyChanged interface on your viewmodel, or make your view model inherit from DependencyObject, and make the properties dependency properties. I won't go into details here, because this is a large subject that you should research on Google before making a decision.
2) Generally speaking, you shouldn't use click events inside your view if you're using MVVM. Instead, create properties on the view model of type ICommand (and create ICommand implementations to match, or use an implementation of DelegateCommand (google it) which will allow you to use delegates to implement the interface. The idea is, your view binds to the property and executes the handler directly inside the viewmodel.
3) If you want to push information from the viewmodel to the view, then you should create an event on the viewmodel and subscribe to it in the view, but this is a last resort, only to be used in cases like displaying a new window, etc. Generally, you should be using binding.
4) To be more specific about what you're doing, you should be binding your Grid's ItemsSource property to some property on the view model. Note, the property on the view model should be of type ObservableCollection<T> if you want to be able to add items and get instant updates.
Hope this helps.
My Main window defines the markup for the application, for this specific scenario lets say I have a grid with 2 columns.
First column will have navigation links, and second column will display the different views.
There are 2 views (and 2 viewmodels) defined in mainwindow xaml:
<Window.Resources>
<DataTemplate DataType="{x:Type vm:Window1ViewModel}">
<vw:Window1View/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:Window2ViewModel}">
<vw:Window2View/>
</DataTemplate>
</Window.Resources>
And in second grid column that displays the views i got :
<ContentControl Content="{Binding Path=ViewModel}" HorizontalAlignment="Left">
</ContentControl>
Where ViewModel is a property that I set accordingly to a view(viewmodel) that i want to display.
Like :
ViewModel = new Window1ViewModel();
(datacontext of the mainwindowview is set to MainWindowViewModel)
So there is no problem to switch between views from the MainWindowViewModel.
My problem is how to switch within Window1ViewModel into Window1ViewMode2?
The various ViewModels don't "know" about other ViewModels.
Only MainWindowViewModel knos about others...
How can I solve this?
Maybe I should define a custom Event (with parameter), MainWindowViewModel will subscribe and other viewmodels will trigger it and then MainWindowViewModel will switch to the needed view?
the solution you describe is one possibility. One other I can think of is using some kind of Navigation-Service (static class or interface you pass to all your child-Viewmodels) that do this kind of work.
If your MainWindowViewModel creates all the others I would stick to the interface solution. You can for example let the MainWindowVM implement such a interface and inject it into all the child-vm on creation. This is much the same as your event-approach but instead of the childs-providing and the main having to subscribe you have the main give something ... IMHO the better approach.
Ok, may be I understood your point. You want that controller actually be modelview which notifies to mainmodelview about the fact that it have to be swapped with someone else.
Considering that we are talking about WPF, create DependecyProperty on mainmodelview , and set it from childview, which in code behind will trigger modelviews swap.
I have the following problem: I'm building a chat WPF application on which I want the user to be connected with different accounts to GTalk. I've made a ViewModel that permits handling the communication but I don't know which is the best way to handle DataContext. I think that I need different DataContexts for every connection instance but I don't know if this is the right way and don't know how to define multiple DataContexts in a View.
A DataContext provides the default binding source for an element in the view. It is inherited from parent to child within the visual tree. You can change the DataContext for any element by binding it to some property of its parent DataContext. This is a common way of creating 'islands' that bind to a child view model.
For example, if you have a User view model that has an Address Property, you can render this in an AddressUserControl as follows:
<StackPanel>
... elements bound to properties of User ...
<AddressUserControl DataContext="{Binding Address}"/>
</StackPanel>
If you have a variable number of accounts, you can use the ItemsControl.
The rough idea behind this: You can bind the ItemsControl to a list of "Sub-ViewModels" in your main ViewModel and define a DataTemplate (= a View) for each of them. The DataContext of each DataTemplate is automatically assigned to a corresponding item in your ViewModel's list.
I've built a WPF UserControl View/ViewModel pair: the view XAML handles the layout and bindings, and the ViewModel handles the logic, in-line with the recommended MVVM pattern.
I would like to be able to re-use this as a control.
How do I hide/encapsulate the ViewModel associated with the view, so that I can use the control as I would a standard control [such as a button] ?
i.e. How do I hide the control's viewmodel ?
depends on how you bind ViewModel class to the control.
if you do like this:
YourControl()
{
DataContex = new ViewModel();
}
then I don't see any problems. add reference to your control and use it.
You can create your ViewModel as a StaticResource within your XAML. The problem with setting the DataContext to your ViewModel is that you can't use that you can no longer use your DataContext from the window or page you in which you use the control.
In your XAML declare your ViewModel:
<myNS:MyViewModel x:Key="ViewModel />
Reference your view model within your XAML:
<TextBlock Text="{Binding Source={StaticResource ViewModel}, Path=TextToBind}" />
In your Code Behind you can access and initialize quickly, I usually make a property for easy reference to my view model.
private MyViewModel viewModel
{
get { return this.Resources["ViewModel"] as MyViewModel; }
}