I am playing with mvvm and wpf. Now, my total solution is MVVM-friendly. The only thing i have put in code behind is the "make new product" & close buttons on the mainview.
Now im adding a menubar, and i was wondering if i can put these "make new product" & close Items in code behind, or is this a no go?
Thanks in advance.
The MVVM way to do it is commands. You can consider them as proxies between your declarative XAML and imperative VM.
Create CreateNewProductCommand, implementing ICommand.
Create a handler for the command performing the actual work as part of ICommand interface implementation (conventionally called On*** - OnCreateNewProductCommand) (you may want to pass paramteres for edit, which is supported by the interface too).
Expose your command as property of your VM.
Bind your menu item command (it'll likely have it, just search for properties containing Command) property to that command using standard binding syntax pointing to the relevant property created at a previous step.
This is not the only way to do it. There're more advanced techniques based on interactions/behaviors etc. Some of them would allow you to bypass command creation and bind your UI element event directly to the executable member of your VM.
Related
In Flex (AS3) you can do neat things where you bind a property to an expression/variable/object. e.g. button.enabled = {!obj.name.empty} It makes for very neat GUI validation amongst other things.
I don't see any such facility in Visual Studio GUI designer but wondered if this sort of functionality exists in .Net/C# and if so, to what extent?
I don't see any such facility in Visual Studio GUI designer
In fact there is. Select the form/control in the designer, then go to Properties window and expand the (DataBindings) category. You'll see a couple properties there, and more if you click the (Advanced) item.
to what extent?
It could only bind to a property (no expressions are supported). To make it work, the object providing the property must support property change notification. The standard way is implementing INotifyPropertyChanged interface, but there are also other mechanisms - IBindingListimplementation providing ListChanged event, object providing event named PropertyNameChanged for a PropertyName etc.
As I mentioned, standartly you can bind only to properties. However, at runtime with some helpers you can really bind to a method or expression. I've already provided examples of doing that in the following threads Button enable and disable on text changed event, Exchange UserControls on a Form with data-binding, Custom WinForms data binding with converter not working on nullable type (double?), .Net WinForms design to sync Data and Controls for a single item data binding, and my own question Cross tabular data binding in WPF for more complex scenarios.
Contrary to what some WPF-ers say, there are no WF limits when binding to a custom objects/collections. The only limits are when binding to other control properties because control property notification pattern is not strictly followed like in WPF where it is by design.
I'm currently in the need of setting the SelectedIndex property of my TabControl when a certain event (IEventAggregator) takes place and thought about how I'd implement that.
I came up with 2 possibilities:
Use GetView() provided by ViewAware in order to access my TabControl and set the SelectedIndex to my value
Use a property in my associated ViewModel and bind this property to my TabControl's SelectedIndex property via XAML
Both options are working fine but I personally want to get this question answered since this is not the first time I'm wondering where to implement the functionality in such cases.
I know that the first option won't enable the Notify support but besides that: What would be the proper way?
Having a GetView() method to manipulate the view directly from the viewmodel completely breaks MVVM. You might as well just put all your logic in codebehind. The whole point of MVVM is to abstract away the actual view so that it is decoupled from the logic, and the app can be unit tested.
What if you change your mind about the tabs in the future and decide to show your multiple views some other way? You've now got to start editing your viewmodel to edit the new view instead of just tweaking some XAML.
And for unit testing you're going to have no way to mock out your TabControl.
I've recently been learning the MVVM pattern in WPF and just started making my first proper, rather big application. So far it's all smooth sailing, and I'm liking what I'm seeing a lot. However I recently met something of a stumbling block.
The application is built with a main TabControl, each TabItem containing a pretty big details view.
TabControl inside main View, ItemsSource bound to MainViewModel.OpenTabs
TabItem with data specific View+ViewModel
TabItem with data specific View+ViewModel
TabItem with data specific View+ViewModel
etc...
The OpenTabs collection is an ObservableCollection<BaseViewModel> on MainViewModel, and the TabControl's SelectedItem is bound to MainViewModel.ActiveTab.
So far so good! However, what I'm not sure I'm getting is how to handle closing of tabs while at the same time following MVVM. If I wasn't trying to be strict with the MVVM (in order to learn it properly), I'd just bind a MouseDown-event on the TabItem-headers and thus get a reference to the clicked item in that event, removing it from the OpenTabs collection in that way. But - unless I'm mistaken - the interaction logic shouldn't need references to actual UI items in order to be effective and proper MVVM.
So, how do I handle this MVVM style? Do I use a command that sends a specific parameter with it to my MainViewModel? It seems like the preferred implementation of ICommand in MVVM doesn't take object parameters (looking at MVVM Light as well as some other tutorials).
Should I just create a CloseTab(int id) public method on my MainViewModel and call that from the view codebehind after catching the Click on my TabItem close button? This seems like MVVM-cheating. :)
Also a final note - this should work even if I click close on a TabItem that isn't the currently active one. Otherwise it wouldn't be hard to setup with OpenTabs.Remove(ActiveTab).
Thanks for any help! I'd also appreciate any links to recommended reading/watching regarding these problems.
Solution: It seems the best way is to use a command that can accept command parameters. I used the RelayCommand from MVVM Light framework:
In MainViewModel:
CloseTabCommand = new RelayCommand<BaseViewModel>((vm) =>
{
OpenTabs.Remove(vm);
});
In XAML:
<Button
Command="{Binding Source={StaticResource MainViewModel}, Path=CloseTabCommand}"
CommandParameter="{Binding}">
Note: Your binding paths may of course vary depending on how your Views and ViewModels are set up.
The best and the right way is to create the command. In different frameworks ICommand usually has two implementation, with the parameter and without one (as often you do not need it).
MVVM light has two ICommand implementation as well: RelayCommand and RelayCommand<T>
I suggest creating your own DelegateCommand implementation, a good example on how to this can be found here or here. Or use the Prism variant, you can download it here.
With a DelegateCommand you can pass arguments down to your ViewModel.
I am required to use the mvvm pattern. I know that the viewmodel should not care about the view from what I been reading. As a result I don't know how to solve this problem:
I have a dll that basically turns a textbox and listview into an autocomplete control:
SomeDll.InitAutocomplete<string>(TextBox1, ListView1, SomeObservableCollection);
anyways I don't know how to call that method from the viewmodel using the mvvm patter. if I reference the controls in the view I will be braking the rules.
I am new to MVVM pattern and my company requires me to follow it. what will be the most appropriate way of solving this problem?
I know I will be able to solve it by passing the entire view to the viewmodel as a constructor parameter but that will totaly break the mvvm pattern just because I need to reference two controls in the view.
What you're doing here is a pure view concern, so I'd recommend doing it in the view (i.e. the code-behind). The view knows about the VM and its observable collection, so why not let the code behind make this call?
(I'd also recommend seeing if you can get a non-code/XAML API for "SomeDll", but I have no idea how much control you might have over that)
There are two things that I'd point out here -
First, this is effectively all View-layer code. As such, using code behind isn't necessarily a violation of MVVM - you're not bridging that View->ViewModel layer by including some code in the code behind, if necessary.
That being said, this is often handled more elegantly in one of two ways -
You could wrap this functionality into a new control - effectively an AutoCompleteTextBox control. This would allow you to include the "textbox" and "listview" visual elements into the control template, and bind to the completion items within Xaml.
You could turn this into an attached property (or Blend behavior), which would allow you to "attach" it to a text box, and add that functionality (all within xaml). The items collection would then become a binding on the attached property (or behavior).
I have a few questions regarding WPF commands.
Where should I put confirmation dialogs? Should I show them right inside the command callback function? What if in some areas in the application I don't want a command to show a confirmation?
If I have a user control that shows items that can be deleted. Should the command be in the application's view model, and I use it for the item deletion, or should the user control itself also have a command that in turn calls the view model's function? (Note: the application view model is the only one having the information needed to do this operation)
How can I pass data within a command? I am using mostly DelegateCommand, and upon firing a command for a grid item, I'd like to pass the selected item, otherwise the application's main view model would have to find the grid and figure out its selection which will hardcode the command to the grid and not make it reusable.
A bit of this is opinion and style . . . Here's my approach:
Question 1:
I have a utility class that handles any confirmation, and I use the lightweight messaging in MVVM Light to handle communication between the view, the confirmation, and the viewmodel.
Edit: A bit more information on point 1
From within my Command, I will send a message along the lines of
"ConfirmDeletionMessage", which is then picked up by my dialog utility
class. The dialog utility class displays the appropriate message to
the user, and checks the results. Based on the results, it will
either broadcast a "DeletionConfirmedMessage" or
"DeletionCanceledMessage," which is then handled by the ViewModel to
either complete or cancel the delete.
There is some risk involved if you have multiple subscribers to this
message, as you won't know what order they're going to be handled,
but if you have strict management on message consumers, or ensure
that they are able to run in a random order, this approach works
pretty well, and it separates your View and Model code in a testable
fashion.
Question 2:
This is a tough one, and it is going to depend on your overall application. I'm personally a fan of putting it in the item's viewmodel. That way, you don't have to worry about your third question as much. Instead, the delete action simply works on the item you're dealing with. However, if you have to act on data outside of your list item (like removing it from the list), it makes more sense for the command to be on the parent viewmodel.
Question 3:
Use the CommandParameter property. You can bind this to whatever you want.
EDIT to Answer #2
Mark Green (who commented below) got me thinking. I originally adopted this approach for WP7, and it absolutely suited what I needed to do. However, there are other ways of handling this that should absolutely be considered. Another option is a "confirmation class" that can be used by your viewmodel. If you are using an IoC kernel, this becomes easy to do with constructor / property injection. Alternatively, if you have other methods of getting the class, do so, but do it in a way that you can mock out in testing. It might look something like this:
public class ExampleViewmodel : ViewModel
{
private IConfirmDialogManager _dialogManager;
public ExampleViewmodel(IConfirmDialogManager dialog)
{
_dialogManager = dialog;
}
// ... code happens ...
private void DeleteCommand()
{
bool result = _dialogManager.Confirm("Are you sure you want to delete?");
}
}
With an IConfirmDialogManager interface that looks like this:
public interface IConfirmDialogManager
{
bool Confirm(string message);
}
Which you would then implement appropriately.
Where should I put confirmation dialogs? Should I show them right inside the command callback function? What if in some areas in the application I don't want a command to show a confirmation?
Confirmation dialogs and show message dialogs are views.
Your VM should have a way of notifying your view that it wants to display something or ask something, then the view should decide how to display it (status bar, window, pop-up, voice message, ...)
If I have a user control that shows items that can be deleted. Should the command be in the application's view model, and I use it for the item deletion, or should the user control itself also have a command that in turn calls the view model's function? (Note: the application view model is the only one having the information needed to do this operation)
The items control should raise a delete command. The VM should handle the command and decide what to do (the VM should have the list of the selected items and the view should be binding to that list).
How can I pass data within a command? I am using mostly DelegateCommand, and upon firing a command for a grid item, I'd like to pass the selected item, otherwise the application's main view model would have to find the grid and figure out its selection which will hardcode the command to the grid and not make it reusable.
Commands can have parameters (e.g. RoutedUICommand). The command binding can specify a binding expression for the parameter. However, the correct approach is for the VM to be the source of the selection with a two way binding between the view's selection and the VM's.
simply use a dialogservice in your viewmodel
it depends but nevertheless the object/viewmodel where the command is located can easily reached with RelativeSource binding
CommandParameter is one way. in fact you use mvvm all information you need should be bind to your viewmodel. so if you have a command and you need the selecteditem from a listview, you can bind it to the viewmodel and dont need to set this as commandparameter