MVVM - Menu View with Preview View (Shared ViewModel) approach - wpf

I've just started my journey with MVVM and WPF and I need an advice to solve my problem or rather guide me towards right solution.
Link to image: https://s12.postimg.org/md0h6fv3x/Simple_App.png
Description (what I want to achieve):
View A is a menu (UserControl) with ListBox and DataContext: V.ObservableCollection
View B is a preview to selected item from View A ListBox
View A & B are loaded from MainWindow
What is simpliest and cleanest approach to achieve that?
I was thinking about sharing the same ViewModel with View A&B.
Create a SelectedItem property in ViewModel and then put it MainWindow's resources and bind datacontext to View A & B
Is it valid approach? Will that VM be updated properly in both views if it get changed?
Somehow bind View's A listbox SelectedItem to View B preview mode but don't know how.

Use only one ViewModel.
Eg; Pseudo code :
public class ViewModel : INotifyPropertyChanged
{
public ObservableCollection<Employee>{get;}
/* provide change notification in ChosenItem */
public Employee ChosenItem{get;set;}
}
Use this ViewModel as DataContext for both Views.

Related

WPF mainwindow controls binding property changed from another window

I`m new to WPF and databinding so I stumbled on something.
I have created an app with vb.net where my MainWindow contains controls and a frame in which I load a page.
On the page I have a listview where the data is loaded from the database.
Now, I have created the Viewmodel and set up the properties to bind to the controls on the Mainwindow so I could set IsEnabled property to True or False through the INotifyPropertyChanged.
If I change the properties from the mainwindow code, is working. What I want to be able to do is when I click on an item on the page-listview to change the properties in the viewmodel and reflect it back to the UI of the Mainwindow.
I`v searched and could not find anything to help me out.
Does anyone have a suggestion on how can I achieve this or some directions to the right place where to find useful information or at least what needs to be used so I can research more of it?
Cheers,
If the "Child" viewmodel has a reference to the "Parent" viewmodel it can update the properties on the parent and the INotifyPropertyChanged system should update the UI for you.
I'm not entirely sure this is what you are asking about though, your question is a little unclear.

How can I easily expose bindable properties of nested controls from a custom UserControl?

My first question here on the Stack. Forgive me for the bad explanation in advance.
I am working on my first MVVM application (Silverlight). I have a custom user control that contains a ListBox to show navigation items. This control is placed in my main xaml page. I don't know if I need to create a composite view model (my main page view model) with a view model especially for the custom control in it or if there is some way to elevate the ListBox properties that I need to bind to.
Through XAML I don't know how to bind, let's say, the ItemsSource property of the ListBox inside the custom control to my main page viewmodel. Basically, I'm at the point that I am questioning my design decision for trying to bind the custom control through my main page view model.
What I have done so far is create dependency properties for the custom control and try to tunnel those dependency properties down to the ListBox properties. I've achieved success with this method for ItemsSource but am having issues with SelectedItem.
Even if I do get SelectedItem to work, it still feels Wrong. Thanks for any advice in advance.
The UserControl should inherit the DataContext from its parent control, unless you are setting it directly. You can then bind to the properties on your view model from your UserControl.
If you would like to create a ViewModel specifically for the UserControl, you can also do that. You would then expose it as a property on your main ViewModel, and bind to it in the MainPage. Example:
public class MainViewModel
{
public ChildViewModel ChildInfo { get; private set; }
}
And then in the view:
<Grid>
...
<lcl:ChildView DataContext="{Binding ChildInfo}" />
...
</Grid>
Your ChildViewModel would then contain properties like SelectedItem to bind your ListBox to.

Silverlight MVVM: MainView w/ SubViews OR MainViewModel w/SubViewModels

I have a MainView with a Tabbed UI.
How do I add a new TabItem (= View) to the TabControl?
Basicaly I see 2 ways:
1.)
* from code in the MainView I can add a new tab.
* the new tab contains a view with a referece to it's viewmodel.
2.)
* from code in the MainViewModel I can add a new viewmodel to a List of childViewModels
* the tabcontrol of the mainView is bound to that list
I prefere case #1 somehow, cause I think the view should know and instanciate it's VM (maybe by using the MVVM light ViewModelLocator) and not the other way round.
But how can I refere from the newly created VM to the MainVM? For example: the MainVM has a property 'IsAdmin'; how can I access (bind) that property from the SubViewModel?
alternative #2: how does the TabControl know, which view should be "rendered" for different ViewModels? How can I "map" from the SubViewModels to the corresponding "SubViews"?
Thanks for sharing your ideas!
I would check out this SO post as the answer can be applied to helping you with your problem.
In the spirit of MVVM, you will want to follow alternative #2. Let your ViewModel logic help you determine which "tabs" you need to display and use DataTemplates to represent those objects. Then you will get them bound to the DataContext of the View and your binding in the DataTemplate (View) will work correctly.
Thomas,
MVVM really is MVVMC. I would advise having a controller for the MainView which contains a method for creating a new tab. If the TabControl is complicated, you might put the functionality in the TabControl itself.
Separation of concerns (MODEL versus VIEWMODEL versus VIEW versus CONTROLLER) is compromised when actuation functionality is located in the models. (M or VM).
Regards,
Guido

How is the DataContext typically set?

I've created a new WPF project, and threw in a DataGrid. Now I'm trying to figure out the easiest way to bind a collection of data to it.
The example I downloaded seems to do it in the window c'tor:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
But then the bindings don't seem to appear in the Visual Studio's Properties window. I'm pretty sure there's a way to set the data context in XAML too... it would make me even happier if I could do it directly through the properties window, but all the Binding options are empty. What's the typical approach?
Edit: At 14 minutes, he starts to talk about other methods of setting the data context, such as static resources, and some "injection" method. I want to learn more about those!
What I typically do is use MVVM. You can implement a simplified version by setting the data context in your code behind and having a model type class that holds your data.
Example: In your code behind
DataContext = Model; // where Model is an instance of your model
then in your view
<DataGrid .... ItemsSource="{Binding SomeProperty}">....
Where SomeProperty is an enumerable property on your view model
You can also set a data context in XAML by using the DataContext property
<uc:SomeUserControl DataContext="{Binding AnotherProperty}"....
This will run your user control within the DataContext of the AnotherProperty on your model.
Note that this is grosely simplified but it'll get you on your way.
Have a look at the MVVM design pattern. This pattern is very suitable for wpf applications.
There is described where to store your data and how to bind your ui to the data.

How do I databind to a ViewModel in Expression Blend?

In WPF and Silverlight you can make a view model object and set it into the DataContext of a control when the control is constructed at runtime. You can then bind properties of the visual object to properties in your DataContext.
One way to set the binding is to type the binding directly into the tag:
<TextBox Text="{Binding Path=Description}"/>
And this will bind the textbox to the Description property in the view model.
The problem with typing in the binding is that you may make a typing mistake. (And you will almost certainly make a mistake if you have hundreds of bindings to make.)
In Expression Blend there is a little white dot beside the Text property in the Properties window. This brings up a menu from which you can Create Data Binding.
How can I get my view model properties to show in the Create Data Binding dialog so that I can select them.
Will the configuration of data binding in Blend interfere with setting my view model into the DataContext at runtime?
One technique is to include the VM as a resource in your view:
<UserControl>
<UserControl.Resources>
<local:YourViewModel x:Key="ViewModel"/>
</UserControl.Resources>
</UserControl>
You can then reference that as DataContext="{StaticResource ViewModel}" elsewhere.
Can't say I like it, but I can't say I like any of the view-first idiosynchrasies that Blend imposes on your design.
I experimented with Blend to find the drag and drop approach to data binding which still lets you override your view model in code easily.
First make your view model object which implements INotifyPropertyChanged and raises the notify event in the setters. The view models can be hierarchical. For example you could have an ObservableCollection within your main view model.
In Blend open up your page or control and go to the data tab.
On the right open the menu under the "Add live data source" icon.
Pick "Define new object data source"
Select your top level view model class and confirm the dialog
In my experiments I found that it was important to bind the data source to where I wanted it first or else Blend might make a less than optimal configuration if I didn't do the next step first.
Open the Objects and Timeline window in Blend
Select the root object, for example UserControl
Open Properties and verify that the root object is selected
Find DataContext and click the square to open the menu and select DataBinding
Select the data source that was just previously created
Now that the data source has been created data binding is very easy.
put some controls on the page
open the Data window
from the DataSource for your view model drag properties onto the controls to create the bindings or set the binding from the Properties window.
Now you can create you live view model object in the constructor of the control
public MainPage()
{
// Required to initialize variables
InitializeComponent();
mVm = new MyViewModel();
this.DataContext = mVm;
}
private MyViewModel mVm;
Add any initialization to retrieve data and you are ready to go.
I have a screen cast on my blog Blendable MVVM : Introduction and Databinding which shows setting this up for Siverlight.
Essentially you create the ViewModel as the DataContext of the UserControl using the "New Object Initialiser" and then using the "Explicit Data Context" tab of the Binding dialog for the controls themselves.
Hope this helps.

Resources