For my application, I'm updating a lot of my controls to better incorporate the MVVM pattern because when I originally started the project I had never used WPF before.
My question is if it is possible to go too crazy with data binding, or should I use it almost exclusively?
For example, say I have two grids named Grid_Sample1 and Grid_Sample2. These grids are viewable based on a user clicking a button. So I have an event for that button, where I either collapse them or make them visible. Inside the event, I could write the following to hide them:
Grid_Sample1.Visibility = Visibility.Collapsed;
Grid_Sample2.Visibility = Visibility.Collapsed;
Or I could go through the trouble of binding their visibility properties:
private Visibility _grid_Sample1Visibility
public Visibility Grid_Sample1Visibility
{
get
{
return _grid_Sample1Visibility ;
}
set
{
_grid_Sample1Visibility = value;
OnPropertyChanged("Grid_Sample1Visibility");
}
}
And then toggling the visibility through the binding.
What is the preferred approach for seasoned WPF users? Is there any reason to use binding for something this simple?
What is the preferred approach for seasoned WPF users?
The latter, i.e. implementing your application logic in a view model class that is separated from the visual representation defined in the view.
Is there any reason to use binding for something this simple?
The main motivation for the MVVM pattern is that it provides separation of concerns between different components in your application which makes it easier to maintain and evolve over time. Small applications generally tend to grow bigger at some point and it won't hurt you to follow the MVVM guidelines from the very start. MVVM also greatly increases the application's testability and this is true even for the smallest application.
So may advice would be to learn and implement the MVVM pattern. It is the recommended pattern to use when developing XAML based UI applications and there is a reason for this.
Ideally, a view should just contain markup and any view-related logic that doesn't belong in the view model.
Related
My WPF app have one MainWindow.xaml and it contains several DataGrid which is bind to ObservableCollection in MainWindow.xaml.cs.
For example,
public MainWindow()
{
var dg1 = new ObservableCollection<CustomClass1>();
var dg2 = new ObservableCollection<CustomClass2>();
var dg3 = new ObservableCollection<CustomerClass3>();
}
Problem is MainWindow.xaml is getting longer and longer as I keep adding new DataGrid in it.
Can I separate each DataGrid to UserControl or Page?
Or do you know better solution for handling several DataGrid in WPF app?
Thanks in advance!
Yes. It is possible.
In my opinion, it is better to follow the MVVM approach in your case. Hope you are aware of it.
If you are not aware of the approach please learn about it.
You can create 3 different user controls or if you feel one is enough, then one is just enough. Just create a user control and create a corresponding view model for that.
In the viewmodel, you can bind the view’s datagrids’ source to properties, thereby reducing complexity, improving maintainability and readability of your code.
You will also not get the feeling that the MainWindow is getting complicated. Just let the MainWindow have few lines of code, in my opinion.
Yes, you can (and probably should) separate your DataGrids out into separate UserControls. Instead of keeping your collections in the code-behind, consider implementing the Model-View-ViewModel pattern (MVVM). Make sure to set the DataContext of each UserControl to an instance of the relevant View Model. This will prevent your current .xaml/.xaml.cs file from getting too large and will also help to make your components more re-usable.
I am new in wpf and there is something that I don't understand..
Everywhere I am reading about separation of code and UI. So how should it work, even if I can design everything in blend, my code behind has always to react on changes and change visibilities in other situations... So first thing without the names of the controls, the code behind won't compile... And even if I have the names, isn't it far impossible to coordinate this?
What you've described is a typical approach for WinForms where achieving a real separation of UI and logic is not possible as the application is driven by events hooked to specific controls.
However, in WPF you do not use (or don't have to use) events for the communication between UI and the application logic. Main areas worth investigating for you are:
DataContext
Binding
Very broad overview is that the XAML describes the layout and specifies where the layout should get data from. Proper data are present in the data context and the WPF engine is responsible for all the wiring (or the binding).
<TextBlock Text="{Binding Caption}" />
For instance in the code above the Text in the TextBlock will be populated with the value stored in the Caption property in the data context. (Usually the data context is specified on the level of a user control or user window.)
In the code behind there is nothing that is related to the TextBlock or to populating it with the values.
What you will find in the code behind usually is only initialization of the DataContext:
public partial class MyUiClass
{
public MyUiClass()
{
this.Loaded += (sender, e) => { this.DataContext = new MyViewModelClass(); }
}
}
All the data are stored in the class set as a data context (MyViewModelClass in the example above).
As a next step I would recommend to go through some MVVM tutorials (there is quite a few good ones on YouTube).
In the context of the "separation of code and UI" discussion, you aren't separating the Xaml from the Code-Behind. Rather, you are separating the logic from the Xaml and, as a result, separating the logic from the Code-Behind as well.
When a Xaml control is constructed, not only is the xaml "view" constructed but so also is the backing partial class that initializes the control. As a result, you always have a code-behind. It's a fundamental part of how Xaml works.
There is something wrong in architecture you're talking about.
You don't need names of control in the model data. The only thing model data interacts with are events/commands. In that way you have a separation between presentation and data where the model view is a bridge between those two.
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'm a bit confused as to what a viewmodel's role is beyond databinding. I have a menu built in silverlight. The menu has x number of menu items which is determined at runtime. One of the features I would like to add to this is that each menuitem has a different text colour when hovered over.
Is it the role of the view to have a colour selector method or should the view handle this in it's code behind?
Normally I would keep the coloring/styling in XAML if possible - My view of the ViewModel is that it is responsible for providing all the data (ie. not graphical stuff) from the Model in a manner the View can consume.
If it was complex logic that determined the color and it was to be reused - I might be tempted to put it in the ViewModel tho.
The view model is used by the data binding process as a "safe" way to allow you to sort/filter/group the records as seen by a specific control without (necessarily) making changes to the actual bound data set (that is, unless/until you tell it to). (FMI read Bea's article here.)
I agree with Goblin here, in that the presentation aspects like color might be best kept separate in the XAML, for example in the DataTemplate used by that control.