I'm using a simple main window that contains 2 custom User Controls (that i've created)
those user controls has ModelView code file for each (im using MVVM pattern).
each ModelView file contains single Command (and command implementation of Execute and CanExecute).
The problem is that when i need to active each command (through the MainWindow cause the main window holds those custom user controls) i need to change the DataContext
of the Main window to the ViewModel of the control that is currently in focus otherwisw i cant execute the command (the Command binding inside the UserControl.xaml cant find the Command).
I think that tracking after focused UserControl in order to change the MainWindow DataContext is not the way.
Is anyone faced this kind of problem before ??
Thanks.
A way of solving this is by creating a ViewModel for the main window and add two properties to this VM, one for each ViewModel you created before.
This way you can assign the new VM to the DataContext of the Window and Bind the DataContext of each user control to one of the properties.
Put the commands on the correct VM where you want to use it.
Does this make sense?
BTW: you call ModelView what I'd call ViewModel.
Related
I'm working on a project that utilizes WPF, using the Prism library and Unity Container.
I have a mainwindow, which contains a mainviewmodel control which in turn is populated by a collection of user controls.
My goal is to set keyboard focus to the mainviewmodel where I have an EventTrigger InvokeCommandAction which reacts to keyeventsargs...
Currently the only way the command is fired if I use a textbox within the control (or child controls). My goal is to have the mainviewmodel control or grid get and preserve keyboard focus.
Any tips would be appreciated!
//Nathan
Either not understanding your question correctly or you should review the basic concepts of MVVM in a WPF implementation.
The View is the WPF controls.
WPF Window/UserControl files contain WPF markup which is the View.
Controls in a view leverage DataBindings to the DataContext property of either the control itself or the parent containing control (which it will inherit).
DataContext property is set to an instance of an object that is the ViewModel. It contains properties to hold values and commands to execute actions.
So conceptually there is no "mainviewmodel control", there is a MainView which contains controls and may in this case have its DataContext property set to an instance o MainViewModel. (hence my confusion)
Finally, while it is possible and some might even recommend writing UI rules/logic in a view model I haven't found much benefit in it.
You are much better off putting UI logic in the XAML or in the MinView code behind. You can still access the MainViewModel in the code behind by casting the MainView.DataContext property as a MainViewModel.
So for example:
MainView.KeyDown event can be wired up to call MainViewModel.CommandX.Execute();
I am struggling with MVVM in my application. I have there a TabControl whose every Tab hosts a control that allows somehow editing a file. For instance, text files or images. Each control is bound to a class from ViewModel area (as is depict at the diagram). I also have RoutedUICommands. One of these commands is WordWrap and only makes sense in case of text files. This command is used in MenuItem or a Button etc. I'd like to enable it only if a text control is the target for this command. How to do it properly according to MVVM?
More details:
XAML for the Window has:
<Window.CommandBindings>
<CommandBinding Command="local:EditorCommands.WordWrap"
Executed="WordWrapExecuted"
CanExecute="CommandCanBeExecutedWhenAnythingIsOpen"/>
</Window.CommandBindings>
A menu item is used this way:
<MenuItem Command="local:EditorCommands.WordWrap"/>
The first thing is the Executed and CanExecute event handlers: they are in Window class although my understanding if MVVM is, that the logic should be in ViewModel only.
What's more, the sender in these function is an instance of a window. Why is it not a target of the command?
Should I write my own successors of RoutedUICommand for every command?
A RoutedUICommand is not really suited to be used in a view model as it searches the visual tree from the focused element and up for an element that has a matching System.Windows.Input.CommandBinding object in its CommandBindings collection and then executes the Execute delegate for this particular CommandBinding.
Since the command logic should reside in the view model, you don’t want to setup a CommandBinding in the view in order to connect the command to a visual element.
Instead, you should create your own implementation of the ICommand interface or use one that is available in any of the MVVM frameworks out there. MvvmLight for example has a RelayCommand class: https://msdn.microsoft.com/en-us/magazine/dn237302.aspx.
How to use RelayCommand with the MVVM Light framework
And in Prism it is called DelegateCommand:
https://www.codeproject.com/Articles/1055060/DelegateCommand-and-CompositeCommand-in-Prism
Please refer to the following blog post for more information about commands in MVVM: https://blog.magnusmontin.net/2013/06/30/handling-events-in-an-mvvm-wpf-application/
I'm working on a WPF MVVM application. I'm showing some data in a datagrid. I've two buttons to Add and Edit the selected record. I've data in ViewModel and I've to show another window (view) and make sure that ViewModels should have no information about views.
Where should I create its view and viewmodel?
How to get the data back and update datagrid?
How can I achieve this in MVVM?
We have not yet decided to use any framework, so I've to create my own interface.
Note: This ended up being quite a long answer - please ask me if anything is unclear
The implementation of dialog windows is a contentious issue in MVVM designs, and different people use different approaches.
Like you, I've decided not to use any framework and implement most things by hand. When it comes to dialog windows, I choose to be pragmatic about my implementation of MVVM, by launching the Dialog Window from inside my ViewModel. Also, I allow each Dialog ViewModel to have a reference to the Window it is displayed in, so it can close it when appropriate (details below). This breaks some of the strict MVVM "rules", but it gets the job done.
The main downside of this is that it might break unit testing if you are testing something that goes through a dialog. However, you can go a long way without running into that problem and it has not bothered me yet.
I've built up a bit of a library of dialog ViewModels which I can easily extend. It's way too much code to post here, but I'll show you the highlights.
Base ViewModel for Dialogs
Each of my dialog windows has a ViewModel that inherits from DialogViewModelBase, which is similiar to my regular ViewModelBase in that it provides support for INotifyPropertyChanged etc. The interesting part is this public method, which I call from wherever to launch the Dialog:
/// <summary>
/// Creates window instance for this dialog viewmodel and displays it, getting the dialog result.
/// </summary>
public void ShowDialogWindow()
{
// This is a property of the DialogViewModelBase class - thus, each DialogViewModel holds a reference to its own DialogWindow:
this.DialogWindow = new Dialogs.Views.DialogWindow();
// Tell the DialogWindow to display this ViewModel:
this.DialogWindow.DataContext = this;
// Launch the Window, using a method of the Window baseclass, that only returns when the window is closed:
this.DialogWindow.ShowDialog();
}
Window launched in the above method will close when its Window.DialogResult property is set. This is why the DialogWindow is a property of the DialogViewModelBase class - when the subclassing dialog ViewModel wants to close the dialog window, it simply sets the result:
protected void CloseDialogWithResult(bool dialogWindowResult)
{
// Setting this property automatically closes the dialog window:
this.DialogWindow.DialogResult = dialogWindowResult;
}
Host Window for Dialog Views
The Dialogs.Views.DialogWindow class that the ShowDialogWindow method instantiates is defined in XAML and is a subclass of Window. It has two important features. The first is that it's primary content element is simply a ContentControl that binds to the current context. This allows me to define different Views for different subclasses of DialogViewModelBase, and the DialogWindow will host the corresponding View based on the type of the context:
<ContentControl Content="{Binding}" /> <!-- In reality this is inside a border etc but its simplified here for demonstration -->
The second important feature of the DialogWindow XAML is that it defines which dialog Views go with which dialog ViewModels. Here is a sample:
<Window.Resources>
<!-- DEFAULT ViewModel-View TEMPLATES -->
<DataTemplate DataType="{x:Type dialogs:YesNoMessageBoxDialogViewModel}">
<views:MessageBoxView />
</DataTemplate>
<DataTemplate DataType="{x:Type dialogs:ErrorDialogViewModel}">
<views:ErrorDialogView/>
</DataTemplate>
</Window.Resources>
What all this does, is that I can define dialogs as subclasses to DialogViewModelBase and implement a View for each, and then tell DialogWindow which View its ContentControl must show for which dialog ViewModel.
Launching a Dialog and getting results
Below is a sample from one of my application ViewModels, in which I launch a Dialog Window that allows the user to select an Asset Type for creation:
public void CreateNewAsset()
{
// Instantiate desired Dialog ViewModel:
Dialogs.NewAssetTypeSelectionDialogViewModel dialog = new Dialogs.NewAssetTypeSelectionDialogViewModel();
// Launch Dialog by calling method on Dialog base class:
dialog.ShowDialogWindow();
// Execution will halt here until the Dialog window closes...
// The user's selection is stored in a property on the dialog ViewModel, and can now be retrieved:
CalculatorBase.AssetTypeEnum newAssetType = dialog.AssetType;
switch (newAssetType)
{
// Do stuff based on user's selection...
}
}
PS: I should really write a blog entry about this - when I do, I will post the link here, as the blog entry will probably have more complete code samples.
It depends how you are handling the data. I will assume that changes made in the popup window can be accepted only when user clicks something like save in other case they should be discarded.
So firstly, I would suggest using MVC approach as controller is perfect for such tasks. You build viewmodels in it, assign them o views and show the views. VM's simply keeps data and commands, commands execute methods are kept in controller. In other words you have singleton class which manages your VM's and views.
You should check out Prism framework. It offers great things like view regios where you can inject different user controls on the runtime, commanding and MVC layering out of the box alongside IOC and DI patterns.
I have an application, and I have an assembly.
In the application, I have a window, and in the assembly I have a user control.
There is an instance of the user control in the window.
Both the user control and the window are backed by separate viewmodels.
In the user control, there is a button. The button should be enabled/disabled based on the state of the user control's viewmodel. When the button is clicked, processing needs to be done, based on the information in the user control's viewmodel, but it needs to be done by the window's viewmodel. (There are aspects of what needs to be done that are, and should be, outside of the scope of the user control.)
And here's the twist - this user control won't be used exclusively in this window, it might be used in another, or in a control that is used in a third. The user control can't be allowed to know what kind of window or control contains it, or is handling the process when its button is clicked.
So, what to do?
Define a command in the assembly, and bind the user control's button to it, passing the user control's viewmodel as the command parameter? How, then, do I bind the command to the window's viewmodel?
Or should I define the command in the user control's viewmodel, then raise an event to tell the parent window that the appropriate action needs to be taken?
It's not clear to me which is cleaner.
If you always know that the parent's property is going to be exposed the same with the same name, you can do something like this that has worked for me plenty of times:
Command={Binding Parent.DataContext.SomeCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}
This gets the usercontrol, then goes to the parent and gets that datacontext and binds it to that command. This works when the user control will be encompassed by many windows / controls that expose the same command (you could implement an interface here).
You could then pass the user control's viewmodel to the command (again, implement some interface) like so:
CommandParaemter={Binding }
You could use a Messenger structure to communicate between ViewModels.
MVVMLight contains one that you could use or you could write your own.
Before doing this make sure you did separate the responsibilities correctly or you'll end up with spaghetti-messages-code.
There should be hierarchy with your view models, just like you have with your controls. The main window has a child user-control. The Main View Model should be able to get connected with User Control View Model (and assign it if needed). Here is how I would do it:
public class MainVM:NotificationObject
{
// Make this a Notify Property
public UserVM userVM { get{return _userVM;}; set {_userVM = value; RaisePropertyChanged("userVM");}
public MainVM
{
userVM = new UserVM();
userVM.ExecuteCmd = new DelegateCommand (yourAction);
}
}
public class UserVM:NotificationObject
{
public DelegateCommand ExecuteCmd {get{return _executeCmd;} set{_executeCmd = value; RaisePropertyChanged("ExecuteCmd");
}
}
XAML:
<local:urUserCtrl DataContext={Binding userVM}/>
This is of course psuedocode
Sounds like a case for the Strategy pattern. http://en.wikipedia.org/wiki/Strategy_pattern
Define an interface for a strategy object that can be assigned to the UserControl's viewmodel, (or used to initialise it). The interface defines whatever properties/methods/events are required to enable the strategy object to retrieve from the UserControl viewmodel the data needed for the processing, plus a means of returning the result of the processing back to the UserControl viewmodel.
Then create a concrete implementation of that strategy object that collaberates with the Window's viewmodel to perform whatever task it needs to. In this case the Window's viewmodel might even implement the strategy interface itself.
Other instances of the UserControl in other scenarios can then be initialised with other concrete implementations of the strategy object that perform the same required task, but possibly in very different ways.
I have legacy windows forms user control that exposses several public methods. I wrapped this control on a wpf user control and encapsulated the Methods with a relaycommand on the new wpf usercontrol.
Now my problem is how to use the mvvm pattern to execute the commands on my user control form the viewmodel that is used with the view hosting the new wpf usercontrol.
In viewmodel you have to add a field say
Public ICommand CommandOne
Now this command will create a new RelayCommand object depending upon your requirements/conditions.
Now, you can bind this 'CommandOne' command with any object say button on your control form.
So, whenever the button is clicked then the RelayCommand object will be created and it will execute the action given to it as a parameter.
Hope it works for you.
I Fond out how to get this to work with bindings. Need to set the mode to OneWayToSource to get the command from the user control. The tricky part is that the initialization of the command has to be done inside the loaded event of the usercontrol. If you try to do it inside of the constructor, you will end up with the default initialization from the binding which could be null.
Use PRISM EventAggregator? You can fireoff an event from ViewModel, from your Usercontrol subscribe to it.
http://www.codeproject.com/Articles/355473/Prism-EventAggregator-Sample
https://msdn.microsoft.com/en-us/library/ff921122.aspx