6
votes

I'm creating a wpf user control which is in mvvm pattern. So we have : view(with no code in codebehind file), viewmodel,model,dataaccess files.

I have MainWindow.xaml as a view file, which I need to bind with MainWindowModel.cs.

Usually, in a a wpf application we can do this with onStartUp event in App.xaml file. But in user control, as we do not have App.xaml...How do I achieve it ?

Please help :(...Thanks in Advance !!!

6

6 Answers

17
votes

You can use a ContentControl, with a DataTemplate to bind the UserControl (View) to the ViewModel :

<DataTemplate DataType="{x:Type vm:MyViewModel}">
    <v:MyUserControl />
</DataTemplate>

...

<ContentControl Content="{Binding Current}" />

WPF will pick the DataTemplate automatically based on the type of the Content

5
votes

I know this is an old, answered question, but I have a different approach. I like to make implicit relationships in the App.xaml file:

<Application.Resources>
    <DataTemplate DataType="{x:Type ViewModels:KioskViewModel}">
        <Views:KioskView />
    </DataTemplate>
</Application.Resources>

With this, there is no need to set a DataContext anywhere.

UPDATE >>>

In response to @Vignesh Natraj's request, here is a fuller explanation:

Once you have set up the DataTemplate in a Resources element, you can display the KioskView in this example by adding an instance of the KioskViewModel anywhere in your XAML. This could be filling the MainWindow, or just inside a particular section of the screen. You could also host multiple instances of the KioskViewModel in a ListBox and it will generate multiple KioskView instances.

You can add an instance of the KioskViewModel to your XAML in a couple of ways, depending on your requirements. One way is to declare the XML namespace for the project that contains the KioskViewModel.cs file and simply add an instance of it in a ContentControl to the page where you want your view to appear. For example, if you had a UserControl called MainView and the KioskViewModel.cs file was in a Kiosk.ViewModels namespace, you could use basic XAML like this:

<UserControl x:Class="Kiosk.Views.MainView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ViewModels="clr-namespace:Kiosk.ViewModels">
    <UserControl.Resources>
        <ViewModels:KioskViewModel x:Key="KioskViewModel" />
        <DataTemplate DataType="{x:Type ViewModels:KioskViewModel}">
            <Views:KioskView />
        </DataTemplate>
    </UserControl.Resources>
    <ContentControl Content="{StaticResource KioskViewModel}" />
</UserControl>

I prefer to use the MVVM design pattern with WPF, so I would have a base view model class providing useful functionality such as implementing the essential INotifyPropertyChanged interface. I then have a property called ViewModel in the main (top level) view model of type BaseViewModel. This provides me with a nice way to change the ViewModel property to any view model that has derived from BaseViewModel and therefore to be able to change the associated view from the view model.

For example, in the MainViewModel.cs class that is bound to MainView there is a field and relating property:

private BaseViewModel viewModel = new KioskViewModel();
public BaseViewModel ViewModel
{
    get { return viewModel; }
    set { viewModel = value; NotifyPropertyChanged("ViewModel"); }
}

As you can see, it starts off as a KioskViewModel instance, but can be changed to any other view at any time in response to user interaction. For this setup, the XAML is very similar, but instead of declaring an instance of the view model in the Resources element, we bind to the property in the MainViewModel:

<UserControl x:Class="Kiosk.Views.MainView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ViewModels="clr-namespace:Kiosk.ViewModels">
    <ContentControl Content="{Binding ViewModel}" />
</UserControl>

Note that for this example, we would need to declare two (or more to make this approach useful) DataTemplates in the App.xaml file:

<Application.Resources>
    <DataTemplate DataType="{x:Type ViewModels:MainViewModel}">
        <Views:MainView />
    </DataTemplate>
    <DataTemplate DataType="{x:Type ViewModels:KioskViewModel}">
        <Views:KioskView />
    </DataTemplate>
</Application.Resources>
2
votes

I've been using MVVM Light Toolkit which has a ViewModelLocator class that you can put properties to the viewmodels in. You then create a reference to the ViewModelLocator in your Mainwindow.xaml like so:

<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True"/>

In the grid panel, or whatever you're using, you can then set the datacontext like this:

<Grid DataContext="{Binding MainWindowViewModel, Source={StaticResource Locator}}">
...
</Grid>

You could also go with MEFedMVVM which potentially adds a bit more flexibility in terms of being able to swap different viewModel implementations into the view.

The flexibility in both of these libraries is that you don't have to use their ViewModel base classes if you don't want to - the ViewModelLocator and the MEFedMVVM can work with any class.

2
votes

There are endless ways to do it, wich all fall in one of the two categories:"view first" or "model first".

In a "view first" mode the view (e.g. your mainwindow) is created first and then (e.g. in the codebehind) the View instantiates the ViewModel and sets it as its datacontext):

private void WindowLoaded(object sender, EventArgs args)
{
   this.DataContext = ViewModelService.GetViewModelX();
}

In a "model first" mode the ViewModel is there first and then instanciated the View.

// method of the viewmodel 
public void LoadView()
{
     // in this example the view abstracted using an interface
     this.View = ViewService.GetViewX();
     this.View.SetDataContext(this);
     this.View.Show();    
}

The examples given here are just one way of many. You could look at the various MVVM frameworks and see how they do it.

0
votes

We can use ObjectDataProvider to call a method inside an object ..as follows :

<ObjectDataProvider ObjectType="{x:Type local:TemperatureScale}"
                    MethodName="ConvertTemp" 
                    x:Key="convertTemp">

Is there anyway to do the same using DataTemplate

0
votes

You can probably look at MSDN. I find it as a good resource, though it doesn't explain how to use usercontrols,you will find your way out.