I'm trying to learn WPF/MVVM, and I'm currently working on how to switch between views. I've started by finding some example to study in the interntet. The one I'm using is quite simple: two views (named "Home and "Account") that only display a label, to keep the xaml and VM simple, and a main window with two buttons to switch between the views.
The DataTemplates are declared in the App.xaml file (together with the namespaces), so they should be global to the whole project:
<Application.Resources>
<DataTemplate DataType="{x:Type viewmodels:HomeViewModel}">
<views:HomeView/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodels:AccountViewModel}">
<views:AccountView/>
</DataTemplate>
</Application.Resources>
The way I've understood it, the trick is done by a third VM (called MainViewModel.cs) that implements a SelectedViewModel attribute that keeps track of the VM that must be displayed, plus and ICommand bound to the buttons:
private BaseViewModel _selectedViewModel;
public BaseViewModel SelectedViewModel
{
get { return _selectedViewModel; }
set
{
_selectedViewModel = value;
OnPropertyChanged(nameof(SelectedViewModel));
}
}
public ICommand UpdateViewCommand { get; set; }
MainWindow.xaml looks like this:
<ContentControl Grid.Row="0" Content="{Binding SelectedViewModel}"/>
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center">
<Button Margin="10" Width="200" Content="Home" Command="{Binding UpdateViewCommand}" CommandParameter="Home"/>
<Button Margin="10" Width="200" Content="Account" Command="{Binding UpdateViewCommand}" CommandParameter="Account"/>
</StackPanel>
In a separate class file (UpdateViewModel.cs) the UpdateViewModel class implements the Execute method as follows:
public void Execute (object parameter)
{
if (parameter.ToString() == "Home")
{
viewModel.SelectedViewModel = new HomeViewModel();
}
else if (parameter.ToString() == "Account")
{
viewModel.SelectedViewModel = new AccountViewModel();
}
}
I hope I've given the idea without boring you. It all works and lets me understand the basics. Now I wanted to try a variant, i.e. take one view (the "Account" one) and implement a button that would switch directly to the other view. I thought all I had to do was to bind the button to the UpdateViewModel class, and initially I modified the Account.xaml code as follows:
<Button Content="Button" Command="{Binding Path=UpdateViewCommand}" CommandParameter="Home"/>
The program runs, but when I click on the button in the Account view, nothing happens. So I changed this to something more complex:
<UserControl.DataContext>
<src:MainViewModel/>
</UserControl.DataContext>
...
<Button Content="Button" Command="{Binding Path=UpdateViewCommand}" CommandParameter="Home"/>
But the result is the same. I suspect it has to do with the binding, but can't see how to change it. Anybody can help?
Welcome to SO!
Your button bindings are done relative to the current DataContext, so binding to UpdateViewCommand in your AccountView (say) will try to bind to the UpdateViewCommand in your AccountViewModel, rather than your MainViewModel.
There are two ways to solve this. The first is to change your button bindings to bind to the parent's view model instead:
<Button Content="Button" Command="{Binding Path=DataContext.UpdateViewCommand, RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}}" CommandParameter="Home"/>
A major disadvantage here, of course, is that the visual hierarchy your child views reside in may not always be as predictable as this.
The second (better) way is to add UpdateViewCommand handlers to each of your child view models, and then have them pass control on to whatever you actually want to handle it. In practice you would typically create a base class for all your children, to reduce code duplication, and you would create a service (e.g. INavigationService) for them to call. Your MainViewModel (say) would then implement this interface, and you would use dependency injection to inject that reference into the child view models at their moment of creation (or just have the parent pass itself directly into their constructors, if you don't want to use a full DI framework).
Related
I have the following xaml view:
<UserControl x:Class="MyViews.PersonView"
xmlns:views="clr-namespace:MyViews"
[...]
>
[...]
<dxb:BarManager x:Name="MainBarManager">
<dxb:BarManager.Items>
<dxb:BarButtonItem x:Name="bbiPrint"
Content="{Binding Print, Source={StaticResource CommonResources}}"
Command="{Binding PrintPersonsCommand}"
CommandParameter="{Binding PersonsCardView, ElementName=CardUserControl}"
/>
</dxb:BarManager.Items>
<Grid>
<Grid.RowDefinitions>
[...]
</Grid.RowDefinitions>
<views:CardView x:Name="CardUserControl" Grid.Row="2"/>
</Grid>
[...]
</UserControl>
The CardView is defined as follows:
<UserControl x:Class="MyViews.CardView"
[...]>
[...]
<dxg:GridControl ItemsSource="{Binding Persons}" SelectedItems="{Binding SelectedPersons}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" SelectionMode="MultipleRow">
[...]
<dxg:GridControl.View>
<dxg:CardView x:Name="PersonsCardView"
[...]
CardTemplate="{StaticResource DisplayCardTemplate}"
PrintCardViewItemTemplate="{StaticResource PrintCardTemplate}"/>
</dxg:GridControl.View>
[...]
</dxg:GridControl>
</UserControl>
The PrintPersonsCommand is defined as follows in my ViewModel:
public class PersonViewModel
{
public PersonViewModel(...)
{
[...]
PrintPersonsCommand = new Prism.Commands.DelegateCommand<DataViewBase>(PrintPersons, CanPrintPersons);
}
public Prism.Commands.DelegateCommand<DataViewBase> PrintPersonsCommand { get; private set; }
private void PrintPersons(DataViewBase view)
{
_printService.ShowGridViewPrintPreview(view);
}
private bool CanPrintPersons(DataViewBase view)
{
return true;
}
}
Now, when I click the Print button, the above PrintPersons method is always fed with null. How do I pass CardUserControl.PersonsCardView in my MyViews.PersonView xaml above, how do I pass that PersonCardView to my command? In other words, how do I fix
CommandParameter="{Binding PersonsCardView, ElementName=CardUserControl}"
to make it work?
Currently, the only solution I've found to this problem is to replace the Command and CommandParameter with
ItemClick="OnPrintBtnClick"
and then in the PersonView's code-behind file to do:
private void OnPrintBtnClick(object sender, ItemClickEventArgs e)
{
var ctxt = DataContext as PersonViewModel;
ctxt.PrintPersonsCommand.Execute(CardUserControl.PersonsCardView);
}
That works but I can't believe there is no other way. I'm not happy with that solution because I don't have the benefits of using the Command any more, like e.g. the automatic evaluation of the Command's CanExecute method. I could also put the CardView's xaml code in the PersonView.xaml but I like my controls to be in separate files because I have the feeling it's more structured and each user control has its own responsibilities which can nicely be split into separate files. Also, that solution binds my view to my view model too tightly.
Can someone help me out please?
Without changing your existing view and viewmodel hierarchy, I was able to pass the GridControl.View to the PersonViewModel using the Tag property
You can assign the CardView to the Tag property at the bottom of your CardView UserControl, and then access this Tag as CommandParameter.
CardView UserControl
<UserControl x:Class="MyViews.CardView"
[...]>
[...]
<dxg:GridControl ItemsSource="{Binding Persons}" SelectedItems="{Binding SelectedPersons}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" SelectionMode="MultipleRow">
[...]
<dxg:GridControl.View>
<dxg:CardView x:Name="PersonsCardView"
[...]
CardTemplate="{StaticResource DisplayCardTemplate}"
PrintCardViewItemTemplate="{StaticResource PrintCardTemplate}"/>
</dxg:GridControl.View>
[...]
</dxg:GridControl>
<UserControl.Tag>
<Binding ElementName="PersonsCardView"/>
</UserControl.Tag>
</UserControl>
Print Button Xaml:
<dxb:BarButtonItem x:Name="bbiPrint"
Content="{Binding Print, Source={StaticResource CommonResources}}"
Command="{Binding PrintPersonsCommand}"
CommandParameter="{Binding ElementName=CardUserControl, Path=Tag}"
/>
Based on the valuable input of Insane, I came up with the following two cleaner fixes:
Code-behind solution
In the PersonView, use the ItemClick event handler on the Print button:
<dxb:BarButtonItem x:Name="bbiPrint"
Content="{Binding Print, Source={StaticResource CommonResources}}"
ItemClick="OnPrintBtnClick"/>
Adapt the corresponding code-behind file like this:
public partial class PersonView : UserControl
{
readonly IPrintService _printService;
public PersonView(IPrintService printService)
{
_printService = printService;
InitializeComponent();
}
private void OnPrintBtnClick(object sender, ItemClickEventArgs e)
{
_printService.ShowGridViewPrintPreview(CardUserControl.PersonsCardView);
}
}
Because I want to gray-out the Print button when there is no selection, I still need to add some code to make that happen. I can get it by
1. updating the button code to
<dxb:BarButtonItem x:Name="bbiPrint"
Content="{Binding Print, Source={StaticResource CommonResources}}"
ItemClick="OnPrintBtnClick" IsEnabled="{Binding CanPrintPersons}"/>
refreshing the CanPrintPersons property in the PersonViewModel upon Persons selection change
That's it.
CardViewModel solution
In that solution, we have a PersonView with its underlying PersonViewModel and a CardView with its underlying CardViewModel. I will not describe that solution with all the details as it is overkill in my situation but for the sake of completeness, I'll give the main points. Upon clicking the Print button on the PersonView, the PersonViewModel's PrintCommand is called. That command emits a Print event to the CardViewModel which in turn calls its own PrintCommand. That latter command calls
_printService.ShowGridViewPrintPreview(View);
where the View is a CardViewModel's property that is set upon CardView loading with e.g.
<dxmvvm:Interaction.Behaviors>
<dxmvvm:EventToCommand EventName="Loaded" Command="{Binding ViewLoadedCommand}" CommandParameter="{Binding ElementName=PersonsCardView}" />
</dxmvvm:Interaction.Behaviors>
Because I have two child views I want to print, I'd need to add a view model for each one of those. In addition, those two view models plus the PersonViewModel need access to the list of Persons to be printed. In particular, they need a shared access to the same data, so that they are synchronized. A simple way to do that is explained here and is totally doable. But I think it is not worth the trouble for the simple use case I have as it adds more complexity than necessary.
I have a WPF application with multiple views. I want to switch from view 1 to view 2 and from there I can switch to multiple views. So I want a button on view 1 that loads view2 in the same window.
I tried those things, but can't get it to work.
How to navigate through windows with MVVM Light for WPF?
https://galasoft.ch/posts/2011/01/navigation-in-a-wp7-application-with-mvvm-light
From the first link, the problem is that I don't understand the ViewModelLocator code. They call the CreateMain(); function but where is this defined, and how can I switch to another view from inside a view.
Firstly, you don't need any of those toolkits/frameworks to implement MVVM. It can be as simple as this... let's assume that we have a MainViewModel, and PersonViewModel and a CompanyViewModel, each with their own related view and each extending an abstract base class BaseViewModel.
In BaseViewModel, we can add common properties and/or ICommand instances and implement the INotifyPropertyChanged interface. As they all extend the BaseViewModel class, we can have this property in the MainViewModel class that can be set to any of our view models:
public BaseViewModel ViewModel { get; set; }
Of course, you'd be implementing the INotifyPropertyChanged interface correctly on your properties unlike this quick example. Now in App.xaml, we declare some simple DataTemplates to connect the views with the view models:
<DataTemplate DataType="{x:Type ViewModels:MainViewModel}">
<Views:MainView />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:PersonViewModel}">
<Views:PersonView />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:CompanyViewModel}">
<Views:CompanyView />
</DataTemplate>
Now, wherever we use one of our BaseViewModel instances in our application, these DataTemplates will tell the framework to display the related view instead. We can display them like this:
<ContentControl Content="{Binding ViewModel}" />
So all we need to do now to switch to a new view is to set the ViewModel property from the MainViewModel class:
ViewModel = new PersonViewModel();
Finally, how do we change the views from other views? Well there are several possible ways to do this, but the easiest way is to add a Binding from the child view directly to an ICommand in the MainViewModel. I use a custom version of the RelayComand, but you can use any type you like and I'm guessing that you'll get the picture:
public ICommand DisplayPersonView
{
get { return new ActionCommand(action => ViewModel = new PersonViewModel(),
canExecute => !IsViewModelOfType<Person>()); }
}
In the child view XAML:
<Button Command="{Binding DataContext.DisplayPersonView, RelativeSource=
{RelativeSource AncestorType={x:Type MainView}}, Mode=OneWay}" />
That's it! Enjoy.
When i first started wiht MVVM I also struggled with the different MVVM-frameworks and especially the navigation part. Therefore I use this little tutorial i found, that Rachel Lim has created. It's very nice and well explained.
Have a look at it on the following link:
http://rachel53461.wordpress.com/2011/12/18/navigation-with-mvvm-2/
Hope it helped you :)
Maybe this link will help you. Just set the NavigateTo property to the view which you need to display on the window.
As an example you can do something like
<Window x:Class="MainWindowView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:meffed="http:\\www.codeplex.com\MEFedMVVM"
meffed:ViewModelLocator.NonSharedViewModel="YourViewModel"
WindowStartupLocation="CenterScreen">
<Button meffed:NavigationExtensions.NavigateTo="firstview"
meffed:NavigationExtensions.NavigationHost="{Binding ElementName=_viewContainer}"
meffed:NavigationExtensions.NavigateOnceLoaded="False"
Visibility="Visible" />
<ContentControl x:Name="_viewContainer" Margin="0,0,0,10" />
<Window>
Then the class file would be
public partial class MainWindowView : Window
{
public MainWindowView()
{
InitializeComponent();
}
public ContentControl ViewContainer { get { return _viewContainer; } }
}
Then you can define each view as UserControl and then using the link I gave above bind the button's meffed:NavigationExtensions.NavigateTo="secondView". To target the ContentControl of the Window just use a RelativeSource binding. For e.g
meffed:NavigationExtensions.NavigationHost="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}},Path=ViewContainer}"
In each of the view just see that you annotate the code behind class definition with the [NavigationView("firstview")] and so on.
It is complicated for first time but it will be very easy once you understand the idea.
<ContentControl x:Name="K.I.S.S" Content="{Binding ViewModel, Converter={StaticResource ViewLocator}}"/>
I have two DataTemplates that gets switched depending on the current ViewModel. However whenever I switch my ViewModel, it seems to call the respective View's constructor and calls the InitializeComponent() call within the constructor, which means that whenever I switch the DataTemplate, it generates a new view that is bound to the respective DataTemplate. I am not sure why this is happening but is there a way to prevent the creation of a new View when switching ViewModels?
Below is the DataTemplates located at my MainView.
<Window.Resources>
<DataTemplate DataType="{x:Type viewModels:FirstPanelViewModel}">
<views:FirstPanelView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:SecondPanelViewModel}">
<views:SecondPanelView />
</DataTemplate>
</Window.Resources>
The template is being displayed in a ContentControl.
<ContentControl Grid.Row="1" Content="{Binding CurrentViewModel}" />
This is my SecondPanelView which is the same as my FirstPanelView, it's very simple.
public partial class FirstPanelView
{
public FirstPanelView()
{
InitializeComponent();
}
}
public partial class SecondPanelView
{
public SecondPanelView()
{
InitializeComponent();
}
}
My Ioc makes sure that I generate only one instance of the SecondPanelView
container.Register<IFirstPanelViewModel, FirstPanelViewModel>(new PerContainerLifetime())
container.Register<ISecondPanelViewModel, SecondPanelViewModel>(new PerContainerLifetime());
DataContext is being bounded in each view by a custom markup extension.
DataContext="{Binding Source={common:Locate}, Path=FirstPanelViewModel}"
DataContext="{Binding Source={common:Locate}, Path=SecondPanelViewModel}"
Which is just calling GetInstance of the respective ViewModel.
public IFirstViewModel FirstViewModel
{
get { return _container.GetInstance<IFirstPanelViewModel>(); }
}
public ISecondViewModel SecondViewModel
{
get { return _container.GetInstance<ISecondPanelViewModel>(); }
}
This is an old issue, but I was also struggling with this issue. The answer is to place the view instances directly in the resources and bind them to content controls in the data templates. If you do so, the view is instantiated only once.
<Window.Resources>
<views:FirstPanelView x:Key="FirstPanelViewKey"/>
<views:SecondPanelView x:Key="SecondPanelViewKey"/>
<DataTemplate x:Key="DT1">
<ContentControl Content="{StaticResource FirstPanelViewKey}" />
</DataTemplate>
<DataTemplate x:Key="DT2">
<ContentControl Content="{StaticResource SecondPanelViewKey}" />
</DataTemplate>
</Window.Resources>
I wasn't able to solve my problem even after extending ContentControl. The issue I ran into using that approach is that ContentControl's dependency property was not directly interfacable/overridable which forced me to hack on the existing dependency property. Also the intialization of a DataTemplate seems to fall deeper than the simple ContentControl.
So I decided to change the way that my views are being displayed by simply toggling their visibility. This approach worked for me since I essentially want my views to stay in the background doing its own thing and ready to be interfaced at its previous state in any moment.
I have a WPF application with multiple views. I want to switch from view 1 to view 2 and from there I can switch to multiple views. So I want a button on view 1 that loads view2 in the same window.
I tried those things, but can't get it to work.
How to navigate through windows with MVVM Light for WPF?
https://galasoft.ch/posts/2011/01/navigation-in-a-wp7-application-with-mvvm-light
From the first link, the problem is that I don't understand the ViewModelLocator code. They call the CreateMain(); function but where is this defined, and how can I switch to another view from inside a view.
Firstly, you don't need any of those toolkits/frameworks to implement MVVM. It can be as simple as this... let's assume that we have a MainViewModel, and PersonViewModel and a CompanyViewModel, each with their own related view and each extending an abstract base class BaseViewModel.
In BaseViewModel, we can add common properties and/or ICommand instances and implement the INotifyPropertyChanged interface. As they all extend the BaseViewModel class, we can have this property in the MainViewModel class that can be set to any of our view models:
public BaseViewModel ViewModel { get; set; }
Of course, you'd be implementing the INotifyPropertyChanged interface correctly on your properties unlike this quick example. Now in App.xaml, we declare some simple DataTemplates to connect the views with the view models:
<DataTemplate DataType="{x:Type ViewModels:MainViewModel}">
<Views:MainView />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:PersonViewModel}">
<Views:PersonView />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:CompanyViewModel}">
<Views:CompanyView />
</DataTemplate>
Now, wherever we use one of our BaseViewModel instances in our application, these DataTemplates will tell the framework to display the related view instead. We can display them like this:
<ContentControl Content="{Binding ViewModel}" />
So all we need to do now to switch to a new view is to set the ViewModel property from the MainViewModel class:
ViewModel = new PersonViewModel();
Finally, how do we change the views from other views? Well there are several possible ways to do this, but the easiest way is to add a Binding from the child view directly to an ICommand in the MainViewModel. I use a custom version of the RelayComand, but you can use any type you like and I'm guessing that you'll get the picture:
public ICommand DisplayPersonView
{
get { return new ActionCommand(action => ViewModel = new PersonViewModel(),
canExecute => !IsViewModelOfType<Person>()); }
}
In the child view XAML:
<Button Command="{Binding DataContext.DisplayPersonView, RelativeSource=
{RelativeSource AncestorType={x:Type MainView}}, Mode=OneWay}" />
That's it! Enjoy.
When i first started wiht MVVM I also struggled with the different MVVM-frameworks and especially the navigation part. Therefore I use this little tutorial i found, that Rachel Lim has created. It's very nice and well explained.
Have a look at it on the following link:
http://rachel53461.wordpress.com/2011/12/18/navigation-with-mvvm-2/
Hope it helped you :)
Maybe this link will help you. Just set the NavigateTo property to the view which you need to display on the window.
As an example you can do something like
<Window x:Class="MainWindowView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:meffed="http:\\www.codeplex.com\MEFedMVVM"
meffed:ViewModelLocator.NonSharedViewModel="YourViewModel"
WindowStartupLocation="CenterScreen">
<Button meffed:NavigationExtensions.NavigateTo="firstview"
meffed:NavigationExtensions.NavigationHost="{Binding ElementName=_viewContainer}"
meffed:NavigationExtensions.NavigateOnceLoaded="False"
Visibility="Visible" />
<ContentControl x:Name="_viewContainer" Margin="0,0,0,10" />
<Window>
Then the class file would be
public partial class MainWindowView : Window
{
public MainWindowView()
{
InitializeComponent();
}
public ContentControl ViewContainer { get { return _viewContainer; } }
}
Then you can define each view as UserControl and then using the link I gave above bind the button's meffed:NavigationExtensions.NavigateTo="secondView". To target the ContentControl of the Window just use a RelativeSource binding. For e.g
meffed:NavigationExtensions.NavigationHost="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}},Path=ViewContainer}"
In each of the view just see that you annotate the code behind class definition with the [NavigationView("firstview")] and so on.
It is complicated for first time but it will be very easy once you understand the idea.
<ContentControl x:Name="K.I.S.S" Content="{Binding ViewModel, Converter={StaticResource ViewLocator}}"/>
I have been playing around and looking around on how to Bind a modelview to a view, but i cant seem to work it out.
I have a view called Search and I want to bind it to SearchModelView.
View has one button and one textbox and looks:
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<ComboBox Height="23" HorizontalAlignment="Left" Margin="12,40,0,0" Name="comboBox1" VerticalAlignment="Top" Width="174" />
<Label Content="Client:" Height="28" HorizontalAlignment="Left" Margin="0,12,0,0" Name="label1" VerticalAlignment="Top" Width="71" />
<Label Content="Client Reference:" Height="28" HorizontalAlignment="Left" Margin="0,69,0,0" Name="label2" VerticalAlignment="Top" Width="117" />
<TextBox
x:Name="clientRefTxt"
Text="{Binding Path=ClientRef, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"
Height="23"
HorizontalAlignment="Left"
Margin="12,103,0,0"
VerticalAlignment="Top"
Width="174" />
<Button
Content="Search Debtors"
Height="23"
HorizontalAlignment="Left"
Margin="12,140,0,0"
Name="button1"
VerticalAlignment="Top"
Width="89"
Command="{Binding Path=SearchCommand}"/>
</Grid>
And I want it to bind to SearchViewModel:
namespace Master.ViewModel
{
public class SearchViewModel:WorkspaceViewModel
{
RelayCommand _searchCommand;
readonly Search _search;
#region Search Properties
public string ClientRef
{
get { MessageBox.Show("GET CLIENTREF"); return _search.ClientRef; }
set
{
MessageBox.Show("SET CLIENTREF");
if (value == _search.ClientRef)
return;
_search.ClientRef = value;
base.OnPropertyChanged("ClientRef");
}
}
#endregion
public ICommand SearchCommand
{
get
{
MessageBox.Show("SEARCHCOMMAND");
if (_searchCommand == null)
{
_searchCommand = new RelayCommand(
param=> this.Search(),
param=> this.CanSearch
);
}
return _searchCommand;
}
}
public void Search()
{
MessageBox.Show("SEARCHING");
}
bool CanSearch
{
get { return true; }
}
}
}
I removed all the assemblies at the top but assume that they are all there. Also note that SearchViewModel is in a separate dll, not in the exe with the View.
Any help would be great or at least a pointer in the write direction, I have already read the msdn article on MVVM and that didnt help...I kinda need a better rundown on binding those too pieces.
Thanks in Advance.
P.S.
Some more details:
SearchViewModel belongs to Master.ViewModel
SearchView is part of GUI.View
I have and idea how the binded objects work, im not to sure on how to bind the view to the viewmodel
Is your View a Grid? I've only used UserControl or Window types as Views, but you may have success using a Grid.
Regardless, this is the cleanest way to instantiate the ViewModel with a UserControl View. Just replace the UserControl tags with Grid tags if you're using a Grid.
<UserControl ...(blah blah)
xmlns:viewmodel="clr-namespace:Master.ViewModel">
<UserControl.DataContext>
<viewmodel:SearchViewModel/>
</UserControl.DataContext>
I believe keeping out of the View's code unless necessary is the preferred pattern for MVVM - let the XAML wire things up for you when possible.
You need to set the view's DataContext to an instance of the view model. There are a variety of ways of doing this, including frameworks that wire it up automagically, but the easiest way to get started is to do it in the constructor of the view:
partial class Search : Window
{
public Search()
{
InitializeComponent(); // provided by Visual Studio
DataContext = new SearchViewModel(); // all-important!
}
}
Obviously you may need to provide other information to initialise the SearchViewModel but hopefully this is enough to get you on the right track.
Your will need to bootstrap your application like #itowlson suggests.
But if you have more than one ViewModel you should allow WPF to do it for you. The basic way to do this (which is easy to maintain until you start having more than a dozen views) is to create a DataTemplate to tie the View with your ModelView(which most people call ViewModel).
So the xaml you provided is probably in a UserControl(at least it should be) so you need to do several things
First create a ResourceDictionary
(fast way is to right-click your project and click Add -> Resource Dictionary
In that file(let's name it Resources.xaml) put this :
<DataTemplate DataType="{x:Type vm:SearchViewModel}">
<vw:SearchView>
</DataTemplate>
The above is assuming you put the namespaces vw and vm for View and ViewModel namespaces respectively
Go to your App.xaml and put this:
<Application.Resources>
<ResourceDictionary Source="Resources.xaml"/>
</Application.Resources>
The above will tell WPF that whenever it encounters an object of type SearchViewModel to:
Instantiate a SearchView object
Set it's DataContext to the SearchViewModel object
HTH