I have the following question:
I'm having a couple of Pages, one of the pages is called: StartschermCursussen.xaml and is used in a frame inside my MainWindow.xaml.
MainWindow.xaml
<Window x:Class="ClientWPF.MainWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ClientWPF"
mc:Ignorable="d"
Loaded="Window_Loaded"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Frame Name="sideWindow" HorizontalAlignment="Left" Width="50" Panel.ZIndex="50"/>
<Frame Name="mainWindow" Margin="50,0,0,0" Source="Pages/StartschermCursussen.xaml" NavigationUIVisibility="Hidden"/>
</Grid>
</Window>
Inside my StartschermCursussen.xaml.cs I'm having my Datacontext that is connected to an 'Container' class that holds references and has properties that are connected to my ViewModels.
StartschermCursussen.xaml.cs
public partial class StartschermCursussen : Page
{
public StartschermCursussen()
{
InitializeComponent();
KeepAlive = true;
DataContext = Container;
}
public ItemsContainer Container { get; set; }
}
Container class
public class ItemsContainer
{
public FilterItem FilterItem { get; set; }
public List<CourseDTO> courses { get; set; } = new List<CourseDTO>();
public List<IconItem> IconList { get; set; } = new List<IconItem>();
public ItemsContainer()
{
//One of my ViewModels
FilterItem = new FilterItem();
}
}
Now, I'm having another page called DetailsCursus.xaml.cs. In that page I'm trying to get specific properties from my ViewModels through databinding in xaml to apply changes to them and show them to the end-user etc.
One way how I did this is through constructor overloading inside my StartschermCursussen.xaml.cs.
StartschermCursussen.xaml.cs (Sending data from DataContext -> DetailsCursus.xaml.cs)
private void menuItemDetails_Click(object sender, RoutedEventArgs e)
{
MenuItem menuItem = (MenuItem)sender;
var contextMenu = (ContextMenu)menuItem.Parent;
var item = (DataGrid)contextMenu.PlacementTarget;
CourseDTO toDeleteFromBindedList = (CourseDTO)item.SelectedCells[0].Item;
//Here I'm sending the data through constructor
this.NavigationService.Navigate(new DetailsCursus(toDeleteFromBindedList, Container.IconList));
}
DetailsCursus.xaml.cs
public DetailsCursus(CourseDTO data, List<IconItem> iconList)
{
object[] items = { data, iconList };
InitializeComponent();
DataContext = items;
}
In the above code snippet I put incoming data in an Array and then linked it to my Datacontext. But I have the feeling that this is not the correct way to get data from your Datacontext.
The code snippet below shows how I get to the data in the Datacontext and I show this in the ItemSource of a ComboBox. It works and returns me the results but I feel like I'm doing this the wrong way.
DetailsCursus.xaml
<ComboBox Width="100" Height="30" Grid.Row="1" HorizontalAlignment="Right" Margin="5" ItemsSource="{Binding Path=[1]}" DisplayMemberPath="IconName" />
Would someone please explain to me how to correctly use the Datacontext within the WPF Pages.
Any kind of help is greatly appreciated!
object[] is certainly unconventional choice for DataContext.
You can create a special named class for DetailsCursus view (pretty common, must-do in MVVM pattern), which will do wonders to readability:
public class DetailsCursusViewModel
{
public CourseDTO SelectedCourse { get; set; }
public List<IconItem> IconList { get; set; }
}
private void menuItemDetails_Click(object sender, RoutedEventArgs e)
{
var menuItem = (MenuItem)sender;
var contextMenu = (ContextMenu)menuItem.Parent;
var dg = (DataGrid)contextMenu.PlacementTarget;
var toDeleteFromBindedList = (CourseDTO)dg.SelectedCells[0].Item;
var viewModel = new DetailsCursusViewModel
{
SelectedCourse = toDeleteFromBindedList ,
IconList = Container.IconList
};
var page = new DetailsCursus(viewModel);
this.NavigationService.Navigate(page);
}
public DetailsCursus(DetailsCursusViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel; // fix bindings after this!
}
I also suggest to explore mvvm pattern in WPF, and also check alternatives for navigation (UserControl VS Page in WPF)
Related
I'm writing a 3D modelling program in WPF and Prism using the MVVM format.
I'm using canvases to show the different views (top, front, side) with grid lines. I want the user to be able to adjust the spacing between lines, and I have a TextBox that holds the value, which is bound to a property in the view-model. This parts works fine.
To draw the grid lines using the user's spacing, however, I need to access that property from the View, where the lines are being drawn (in MainWindow.xaml.cs). I still need it to exist in the view-model as well, though, for certain functionality to work (like snap-to-grid).
I foresee that there will be many properties I'll need to bounce back and forth, since the UI and the functionality will be working closely together in a program like this.
The way I've gotten around this problem in the past is by first creating an invisible label in the UI. Then I use a function to set the label's binding dynamically and grab the value from the label.
public int TempIntBind(string bind)
{
DummyLabel.SetBinding(Label.ContentProperty, new Binding(bind));
int newInt;
if (DummyLabel.Content != null && int.TryParse(DummyLabel.Content.ToString(), out newInt))
{
return newInt;
}
else
{
return -1;
}
}
This works, but it seems rather hacky and also circumvents the MVVM pattern.
Is there a better way to achieve this result?
Since:
this.DataContext = new View_Model ();
I was hoping I could just say something like:
x = this.DataContext.gridsize;
But apparently that's not how that works. Too JavaScript-y, I suppose.
Here are the relevant bits of my main window xaml:
<Window x:Class="Brick.MainWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Brick"
mc:Ignorable="d"
Title="Brick" Width="800" Height="600">
<WrapPanel Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="1" Margin="5">
<Label>Grid Size</Label>
<TextBox Width="50" Height="20" Text="{Binding Path=grid_size, UpdateSourceTrigger=PropertyChanged}" />
</WrapPanel>
<Canvas Grid.Column="1" Grid.Row="2" x:Name="top_view" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,5,5" Background="Black"></Canvas>
</Grid>
</Window>
The View:
namespace Brick
{
public partial class MainWindow : Window
{
public MainWindow ()
{
InitializeComponent ();
this.DataContext = new View_Model ();
draw_grid_lines ();
}
void draw_grid_lines ()
{
int spaces = grid_size; // <-- Right here is the problem spot
}
}
}
And the View-Model:
namespace Brick
{
class View_Model : Prism.Mvvm.BindableBase
{
public event PropertyChangedEventHandler property_changed_event;
private int grid_size_private;
public int grid_size
{
get {return grid_size_private;}
set
{
if (grid_size_private != value)
{
grid_size_private = value;
RaisePropertyChanged ("grid_size");
}
}
}
public View_Model ()
{
grid_size = 8;
}
}
}
did you try casting the DataContext to View_Model in code behind?
namespace Brick
{
public partial class MainWindow : Window
{
public MainWindow ()
{
InitializeComponent ();
this.DataContext = new View_Model ();
draw_grid_lines ();
}
void draw_grid_lines ()
{
var vm = (View_Model)this.DataContext;
int spaces = vm.grid_size; // <-- Right here is the problem spot
}
}
}
You can assign a property to DataContext and just access members through it:
namespace WpfApp1
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
Model = new Model();
DataContext = Model;
}
private Model Model { get; }
private void Whatever()
{
var value = Model.Value;
}
}
internal class Model
{
public int Value { get; set; }
}
}
For the syntax issue you were running into you would have done:
var x = ((Model) DataContext).Value;
So my situation is this: I want to be able to use MVVM with my WPF application using MongoDB. I am very new to MVVM (I know very little of it), but I've got some experience using .NET and WPF.
I have a namespace for recalling MongoDB collections, with the Model component stored there as a class called "User"
Model (in a separate namespace):
public class User
{
[BsonElement("_id")]
public ObjectId Id { get; set; }
public string name { get; set; }
// other methods listed here
public async static Task<List<User>> getUserList()
{
// allows me to get a list of users
var col = MongoDBServer<User>.openMongoDB("Users");
var filter = Builders<User>.Filter.Exists("name");
List<User> userList = await col.Find(filter).ToListAsync();
return userList;
}
}
I've created a very basic ViewModelBase (abstract ViewModelBase):
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if(handler == null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
}
And a derived class for handling the User Lists (ViewModel):
public class UserListViewModel : ViewModelBase
{
private User _user;
private ObservableCollection<User> _userList;
public User user
{
get { return _user; }
set
{
_user = value;
OnPropertyChanged("user");
}
}
public ObservableCollection<User> userList
{
get { return _userList; }
set
{
_userList = value;
OnPropertyChanged("userList");
}
}
public UserListViewModel()
{
user = new User();
this.userList = new ObservableCollection<User>();
// since MongoDB operations are asyncrhonous, the async method "getUserList()" is used to fill the observable collection
getUserList().Wait();
}
public async Task getUserList()
{
var UserListRaw = await User.getUserList();
this.userList = new ObservableCollection<User>(UserListRaw);
}
}
The view component is as a simple window with a listbox, as follows (View):
<Window x:Class="UserManagementMVVM.UsersWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:UserManagementMVVM"
mc:Ignorable="d"
Title="UsersWindow" Height="300" Width="300">
<Window.Resources>
<local:UserListViewModel x:Key="ViewModel"/>
<!-- Receiving error for this XAML block saying "Object reference not set to instance of an object -->
</Window.Resources>
<Grid DataContext="{Binding ViewModel}">
<ListBox Margin="5" ItemsSource="{Binding userList}"/>
</Grid>
</Window>
The App.Xaml and its codebehind are left untouched, as is the View's codebehind.
When I run the program, nothing shows up (ie: The Window starts, but the ListBox is empty even though there is data). I will soon add some button functionality that will perform atomic operations with MongoDB.
I've been trying for nearly 2 weeks to make my own MVVM program for this, with no success. Any assistance would be greatly appreciated.
You are not putting the getUserList() return value into a variable
I assume you mean to do the following
Task.Run(async ()=>this.userList = await getUserList());
this shall work you should think wether you want to wait for the task to finish or not, and than place a .Wait() after it.
Your other issue might be the way you bind to the ViewModel in the context it should use StaticResource instead of binding
like This:
<Grid DataContext="{StaticResource ViewModel}">
<Window x:Class="UserManagementMVVM.UsersWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:UserManagementMVVM"
mc:Ignorable="d"
Title="UsersWindow" Height="300" Width="300">
<Window.DataContext>
<!--You have to set the DataContext -->
<local:UserListViewModel x:Key="ViewModel"/>
</Window.DataContext>
<Grid>
<ListBox Margin="5" ItemsSource="{Binding userList}"/>
</Grid>
</Window>
You have to set the DataContext right. i changed your xaml. but i prefer setting the DataContext for the Mainwindow in Codebehind or app.xaml.cs.
eg: app.xaml.cs
protected override void OnStartup(StartupEventArgs e)
{
var data = new MainWindowViewmodel();
this.MainWindow = new MainWindow(data);
this.MainWindow.Show();
}
all other DataContext for my views are done with DataTemplates within the ResourceDictionary
<DataTemplate DataType="{x:Type local:MyOtherViewmodel}">
<local::MyOtherViewmodelView />
</DataTemplate>
I want to give credit to both gilMishal and blindmeis for pointing me in the right direction. Both of your answers have helped. Here is my updated (and functional!) code:
App.xaml.cs has been modified as follows (Credit to blindmeis):
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
UsersWindow window = new UsersWindow();
var ViewModel = new UserListViewModel();
window.DataContext = ViewModel;
window.Show();
}
}
The ViewModel has been updated:
public class UserListViewModel : ViewModelBase
{
private User _user;
private ObservableCollection<string> _userList; // changed from "User" class to string
public User user
{
get { return _user; }
set
{
_user = value;
OnPropertyChanged("user");
}
}
public ObservableCollection<string> userList
{
get { return _userList; }
set
{
_userList = value;
OnPropertyChanged("userList");
}
}
public UserListViewModel()
{
userList = new ObservableCollection<string>();
Task.Run(async () => this.userList = await getUserList()); // Credit to gilMishal
}
public async Task<ObservableCollection<string>> getUserList()
{
var UserListRaw = await User.getUserList();
var userListOC = new ObservableCollection<string>();
foreach (var doc in UserListRaw) // extracting the "name" property from each "User" object
{
userListOC.Add(doc.name);
}
return userListOC;
}
}
And the view:
<Window x:Class="UserManagementMVVM.UsersWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:UserManagementMVVM"
mc:Ignorable="d"
Title="UsersWindow" Height="300" Width="300">
<Window.Resources>
<local:UserListViewModel x:Key="ViewModel"/>
</Window.Resources>
<Grid> <!-- data context removed from here, credit blindmeis -->
<ListBox Margin="5" ItemsSource="{Binding userList}"/>
</Grid>
</Window>
All, I have a custom DataGridView control which overrides the DataGidView's OnItemsSourceChanged event. Inside this event I need to get a reference to a data set in the relevant ViewModel. Code is
public class ResourceDataGrid : DataGrid
{
protected override void OnItemsSourceChanged(
System.Collections.IEnumerable oldValue,
System.Collections.IEnumerable newValue)
{
if (Equals(newValue, oldValue))
return;
base.OnItemsSourceChanged(oldValue, newValue);
ResourceCore.ResourceManager manager = ResourceCore.ResourceManager.Instance();
ResourceDataViewModel resourceDataViewModel = ?? // How do I get my ResourceDataViewModel
List<string> l = manger.GetDataFor(resourceDataViewModel);
...
}
}
On the marked line I want to know how to get a reference to ResourceDataViewModel resourceDataViewModel. The reson is that i have multiple tabs each tab contains a data grid and ascociated ViewModel, the ViewModel holds some data that I need to retrieve [via the ResourceManager] (or is there another, better way?).
The question is, from the above event, how can I get the ascociated ResourceDataViewModel?
Thanks for your time.
Get the DataContext and cast it to the view-model type:
var viewModel = this.DataContext as ResourceDataViewModel
Put a static reference to it on your app, when the VM is created place its reference on the static and access it as needed.
You ask if there is a better way... In my experience if you find yourself subclassing a UI element in WPF there ususally is.
You can get away from embedding business logic (the choice of which data to display in the grid), by databinding your entire tab control to a view model.
To demonstrate - here is a very simple example. This is my XAML for the window hosting the tab control:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TabControl ItemsSource="{Binding Tabs}" SelectedItem="{Binding SelectedTab}">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding TabName}"></Setter>
</Style>
</TabControl.ItemContainerStyle>
<TabControl.ContentTemplate>
<DataTemplate>
<Grid>
<DataGrid ItemsSource="{Binding TabData}"></DataGrid>
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
</Window>
The data context of my window is a TabsViewModel (I am using the NotificationObject that can be found in the PRISM NuGet Package):
public class TabsViewModel: NotificationObject
{
public TabsViewModel()
{
Tabs = new[]
{
new TabViewModel("TAB1", "Data 1 Tab 1", "Data 2 Tab1"),
new TabViewModel("TAB2", "Data 1 Tab 2", "Data 2 Tab2"),
};
}
private TabViewModel _selectedTab;
public TabViewModel SelectedTab
{
get { return _selectedTab; }
set
{
if (Equals(value, _selectedTab)) return;
_selectedTab = value;
RaisePropertyChanged(() => SelectedTab);
}
}
public IEnumerable<TabViewModel> Tabs { get; set; }
}
public class TabViewModel
{
public TabViewModel(string tabName, params string[] data)
{
TabName = tabName;
TabData = data.Select(d => new RowData(){Property1 = d}).ToArray();
}
public string TabName { get; set; }
public RowData[] TabData { get; set; }
}
public class RowData
{
public string Property1 { get; set; }
}
This is obviously an over simplified case, but it means that if there is any business logic about precisely what data to show in each tab, this can reside in one of the view models, as opposed to the code behind. This gives you all the 'separation of concerns' benefits that MVVM is designed to encourage...
The files I have created and will be referring to in this question are:
TechnicainSelectionView.xaml
TechnicianSelectionView.cs
TechnicianSelectionViewModel.cs
Technician.cs (Code First Entity)
I have the following xaml in my TechnicanSelectionView.xaml
<UserControl xmlns etc... here"
d:DesignHeight="48" d:DesignWidth="300">
<Grid>
<StackPanel>
<Label Content="Select a Technican to run the test" FontWeight="Bold"></Label>
<ComboBox ItemsSource="{Binding Technicians, Mode=TwoWay}"></ComboBox>
</StackPanel>
</Grid>
</UserControl>
The Technicians property to which the ItemSource is set to bind to states that it Cannot resolve Technicians due to an unknown DataContext.
So if we look to my TechnicianSelectionView.cs code-behind...
public partial class TechnicianSelectionView : UserControl
{
public TechnicianSelectionViewModel ViewModel { get; private set; }
public TechnicianSelectionView()
{
InitializeComponent();
Technician.GenerateSeedData();
ViewModel = new TechnicianSelectionViewModel();
DataContext = ViewModel;
}
}
... we see that I am setting the view's DataContext to my TechnicianSelectionViewModel ...
public class TechnicianSelectionViewModel : ViewModelBase
{
public ObservableCollection<Technician> Technicians { get; set; }
public TechnicianSelectionViewModel()
{
Technicians = new ObservableCollection<Technician>();
}
public bool IsLoaded { get; private set; }
public void LoadTechnicians()
{
List<Technician> technicians;
using (var db = new TestContext())
{
var query = from tech in db.Technicians
select tech;
foreach (var technician in query)
{
Technicians.Add(technician);
}
}
IsLoaded = true;
}
}
Techicians is a property on my ViewModel...
So having already set the DataContext for the view, why can't it resolve Technicians on the ViewModel as the DataContext/property it is going to bind to?
EDIT:
As per a concern in a comment below. This is a design time problem and not compile time. I should have indicated this at the start.
You need to specify the type of data context in the xaml to get design-time support. Even though you assigned the data context in code-behind, the designer is not going to recognize that.
Try putting the following in your xaml:
d:DataContext="{d:DesignInstance vm:TechnicianSelectionViewModel}"
See this link for more details.
In my Xamarin Forms Xaml file I used the following lines in the header (ContentPage tag) and it worked perfectly as I wanted.
Basically now
the intellisense shows the fields in the binding
my Resharper is able to rename the binding in the Xaml file if I refactor the name of the property
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:vm="clr-namespace:YourApplicationName.ViewModels;assembly=YourApplicationName"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance {x:Type vm:CurrentPageViewModel}}"
I'm very new to WPF and a beginner in C#.NET. I'm currently making an application where there will be many pages and the trigger to change the page is hand gesture using Kinect SDK (the trigger method is not relevant for this question). Normally when a WPF file is created, there will be a similarly named .cs file attached to it, which acts somewhat like a controller. However, I need multiple WPF files/pages to be controlled only by a single controller .cs file. How do I achieve that? Thanks for viewing my question and your answer will be very appreciated :)
You probably want to write a class that contains your 'controller' code and reference it from your WPF UserControls / Pages.
In a new file:
public class MyController
{
public void DoThings(object parameter)
{
// stuff you want to do
}
}
and then inside your UserControl code-behind class:
public partial class MyWpfControl : UserControl
{
private MyController controller;
public MyWpfControl
{
this.controller = new MyController();
}
}
and finally, tie your events back to the controller's method:
private void OnGesture(object sender, EventArgs e)
{
// call the method on the controller, and pass whatever parameters you need...
this.controller.DoThings(e);
}
The code behind is really part of the view and isn't really analogous to a controller and generally there shouldn't be much code in them. Typically you would want most of your logic between your "View Model" which serves as an abstraction of the view and "Model" which serves as an abstraction of the business logic that your UI is interacting with.
In this light what I think you really want is a View Model(VM) that controls multiple views. This is a fairly typical scenario and the preferred method (IMO anyway) is to have a hierarchical view model that has a top level the application model and a number of sub VMs that represent different components within your UI, though you can bind everything to your top level VM if you really want to.
To do this we would first define our view model like so
public interface IGestureSink
{
void DoGesture();
}
public class MyControlVM : INotifyPropertyChanged, IGestureSink
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private ApplicationVM parent;
public MyControlVM(ApplicationVM parent)
{
this.Name = "my user control";
this.parent = parent;
parent.PropertyChanged += (s, o) => PropertyChanged(this, new PropertyChangedEventArgs("Visible"));
}
public String Name { get; set; }
public bool Visible { get { return parent.ControlVisible; } }
public void DoGesture()
{
parent.DoGesture();
}
}
public class ApplicationVM : INotifyPropertyChanged, IGestureSink
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public ApplicationVM()
{
this.ControlVM = new MyControlVM(this);
this.ControlVisible = false;
}
public MyControlVM ControlVM { get; private set; }
public bool ControlVisible {get; set;}
public void DoGesture()
{
this.ControlVisible = !this.ControlVisible;
PropertyChanged(this, new PropertyChangedEventArgs("ControlVisible"));
}
}
and then all we need to do is to build a user control
<UserControl x:Class="WpfApplication2.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid Background="LightBlue">
<Label Content="{Binding Name}"/>
</Grid>
</UserControl>
and page
<Window xmlns:my="clr-namespace:WpfApplication2" x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<Grid>
<my:MyControl Width="200" Height="200" x:Name="myUserControl" DataContext="{Binding ControlVM}" Visibility="{Binding Visible,Converter={StaticResource BooleanToVisibilityConverter}}"/>
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="222,262,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
</Grid>
</Window>
That use it. The only thing that we need in our code behind is a constructor that sets up the page VM and wiring from our button to the view model.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ApplicationVM();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
((IGestureSink)(this.DataContext)).DoGesture();
}
}
If you wanted to use a monolithic view model instead you would use this Instead of binding the DataContext to ControlVM:
<my:MyControl Width="200" Height="200" x:Name="myUserControl" DataContext="{Binding DataContext}" Visibility="{Binding ControlVisible,Converter={StaticResource BooleanToVisibilityConverter}}"/>