I have some UserControl, It's DataContext is binded to the ViewModel,
How to set a ViewModel's property from XAML? Is it possible?
UPD :
Sorry for being not very clear,
I'm trying to get something like this :
UserControl's DataContext is binded to ViewModel, I need to set ViewModel's property to something (let's say, UserControl's Width property).
Is it possible?
UPD2: It seems to be not possible.I know about TwoWay binding mode, etc, thing I wanted to do - to set ViewModel's property to UserControl's one
This example should be very clear
<Set Property={Binding SomePropertyOnViewModel}
Value={Binding RelativeSource={RelativeSource Self},
Path=SomePropertyOnUserControl}>
I am not sure whether I understand the question exactly.
But here is an example.
It will:
Create a view model of type ExampleViewModel inside the user control by setting the user
controls DataContext property in xaml
Create a text box in xaml and bind it to the view models
TextInViewModel string property.
Set up the usual INotifyPropertyChanged interface (this was extracted to the base class ViewModelBase)
Create the view model in xaml and set the user controls data context to it:
<UserControl x:Class="MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Test"
xmlns:viewModel="clr-namespace:ViewModels">
<UserControl.DataContext>
<viewModel:ExampleViewModel/>
</UserControl.DataContext>
<StackPanel Orientation="Horizontal" >
<Label>Enter Text here: </Label>
<TextBox Text="{Binding TextInViewModel}"></TextBox>
</StackPanel>
</UserControl>
ViewModel:
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string prop)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
}
public class ExampleViewModel : ViewModelBase
{
/// <summary>
/// Property bound to textbox in xaml.
/// </summary>
public String TextInViewModel
{
get { return _textInViewModel; }
set
{
_textInViewModel= value;
RaisePropertyChanged("TextInViewModel");
}
}
private string _textInViewModel;
/// <summary>
/// Constructor.
/// </summary>
public ExampleViewModel()
{
}
}
Binding works both ways: i.e. from source (e.g. viewmodel) to target (e.g. usercontrol) and from target back to source.
You specify the direction via Mode of binding.
Following are the BindingModes:
TwoWay
OneWay
OneTime
OneWayToSource
In your case, if you want to bind width property of usercontrol to the TheWidth property of ViewModel:
Case A:
Want to bind in both directions, use Mode=TwoWay
<UserControl Width="{Binding TheWidth, Mode=TwoWay}">
<!-- your rest of code -->
</UserControl>
Case B:
Want to bind only from usercontrol to viewmodel, use Mode=OneWayToSource
<UserControl Width="{Binding TheWidth, Mode=OneWayToSource}">
<!-- your rest of code -->
</UserControl>
XAML
<UserControl.DataContext>
<vm:ViewModel/>
</UserControl.DataContext>
I prefer the ViewModel Locator approach (this is like a service locator pattern for ViewModel).
Because as soon as your ViewModel has constructor parameters, you are either tightly coupled, or you can't use the above described xaml way....
There are many ViewModel-Locator ways. One is described here using MEF and silverlight.
http://johnpapa.net/simple-viewmodel-locator-for-mvvm-the-patients-have-left-the-asylum
here is another one:
http://brendan.enrick.com/post/Wire-up-your-ViewModels-using-a-Service-Locator.aspx
Well, you bind your UI elements to them:
<UserControl Width="{Binding Path=DisplayWidth, Mode=OneWayToSource}">
<Grid>
<TextBox MinWidth=100 Text="{Binding MyProperty}"/>
</Grid>
</UserControl>
assuming a view model like this:
class ViewModel
{
public string MyProperty { get; set; }
public int DisplayWidth { get; set; }
}
Through binding my dear friend..
for example: (Assuming in your context)
If you have class "Person" and your person has a Name and SurName public property and you want to bind it to a textbox. You do the following:
<TextBox Text="{Binding Path=Name}" />
This only works if the name is your public property, it is best practice to make you object ( in this case Person) as a public property and use the Path parameter differently.
Example:
<TextBox Text="{Binding Path=Person.Name}" />
It does clutter your code way less, then to make a property in your viewmodel for every property of any object in your viewmodel.
"How to set a ViewModel's property from XAML? Is it possible?"
So, that seems to be not possible, max you can accomplish - two-way binding, which is, unfortunately not I wanted.
All in all it's rather bad design than a problem
Related
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 am very sorry that this question is very basic. I just learned WPF and I failed to make simple two way binding to textbox.text to string property.
XAML Code:
<Window x:Class="WpfApplication1.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:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="StuInfo">
<TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="10,26,0,0" TextWrapping="Wrap" Text="{Binding Path=str,Mode=TwoWay}" VerticalAlignment="Top" Width="120"/>
<Button x:Name="button" Content="Check" HorizontalAlignment="Left" Margin="10,67,0,0" VerticalAlignment="Top" Width="75" Click="button_Click"/>
</Grid>
C# Code
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
str = "OK";
}
public string str { get; set; }
private void button_Click(object sender, RoutedEventArgs e)
{
Console.WriteLine(str);
}
}
First, the textbox does not show "OK", but it is blank. Then, I typed a different text into the textbox, for ex:"blablabla" without the quotes. Then I click the button to check if my str property has been updated. Apparently, str still contains "OK".
What did I do wrong here? What did I miss to make the binding work?
As a newcomer to WPF, all this Binding and DataContext jazz can be quite confusing. Let's start with your binding expression first...
<TextBox Text="{Binding Path=str, Mode=TwoWay}"/>
What this is saying is that you want to bind your Text property to whatever the DataContext of the TextBox is. DataContext is essentially the "thing" your TextBox is getting it's data from. Now here's the rub. DataContext is inherited from the element "above" it in the visual tree if not explicitly set. In your code, TextBox inherits it's DataContext from the Grid element, which in turn inherits it's DataContext from the Window element. Seeing that DataContext is not set in your Window the default value of the DataContext property will be applied, which is null. The DataContext is also not set in any of the child elements of your window, which, via inheritance, will set the DataContext of all children of that window to null.
It is important to note that you've left out the Source property in your binding expression.
<TextBox Text="{Binding Source=left_out, Path=str, Mode=TwoWay}"/>
When this property is left out, the binding's source is implied to be the elements DataContext, which in this case is null, for the reasons mentioned above. Basically, what your expression is saying here is that you want to bind your text property to DataContext.str which resolved by WPF is null.str.
OK, cool. Now, how do we set the DataContext of your TextBox.Text binding to the Code Behind for the window so we can get at that str property? There are several ways to do this, but for our purposes we'll focus on setting it explicitly in the binding of the TextBox.Text property. Now, there are three different "source" type properties of bindings. "Source" being where we want our control/element's binding to get it's data from. We have Source, RelativeSource, and ElementName. We're only going to focus on ElementName here, but the others are essential to research and understand.
So, let's name our Window element so we can access it through the ElementName property.
<Window x:Class="WpfApplication1.MainWindow"
x:Name="_window"
...
Now we can set the ElementName property on the TextBox.Text binding to refer to the window.
<TextBox Text="{Binding ElementName=_window, Path=str, Mode=TwoWay}"/>
This means the binding will look for the _window.str property when trying to resolve it's binding. At this point, you still probably won't see your str value reflected in the TextBox. This is because it's value is set after the InitializeComponent method in the window's constructor. This function is where bindings are resolved for the first time. If you were to set the value of str before calling InitializeComponent, you would see the value reflected in the TextBox.
This brings us to Dependency Properties. For now, just know that Dependency Properties have built in change notification, which your binding needs so it "knows" when the binding has changed and when to resolve the binding value again. Yes, you could use INotifyPropertyChanged in your code behind, but there are good arguments for using DependencyProperties in this case, which will only confuse the issue at this point. But, it is another one of those things that is essential to understand.
Here is the code for a DependencyProperty for your str property.
public static readonly DependencyProperty StrProperty
= DependencyProperty.Register("Str", typeof(string), typeof(MainWindow),
new FrameworkPropertyMetadata(FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public string Str
{
get{return (string)GetValue(StrProperty);}
set{SetValue(StrProperty,value);}
}
Now you'll be able to set the value like such and have it reflect through the binding to your TextBox.
public MainWindow()
{
InitializeComponent();
Str = "OK";
}
At this point, all should be well. I hope this helps out. It took me a while get the hang of WPF. My suggestion would be to read as much as you can on DataContext, Binding, and DependencyProperty as these are the core of WPF. Good luck!
The problem is that, you dont bind to codebehind of Window, but to DataContext.
Try this:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new DC();
}
public class DC
{
public string str { get; set; }
public DC()
{
str = "OK";
}
}
}
Normally, you would have two different files, but for test, you can do it in one file.
After that, your DC (DataContext) should implement INotifyPropertyChanged interface.
Try to find some article about MVVM like this http://www.codeproject.com/Articles/165368/WPF-MVVM-Quick-Start-Tutorial
I have a UserControl who's DataContext is being set to an instance of a ViewModel (using MVVM). But, I have controls within the UserControl which need to be bound to properties that only pertain to the view (which is why I placed them in code behind). I'm not sure how to bind this in xaml appropriately:
Note: SelectedOrderType is a property on the View-Model, and OrderTypes is a property on the UserControl itself.
<UserControl x:Class="MyNamespace.OrderControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="OrderUserControl">
<Grid>
...
<ComboBox ItemsSource="{Binding Path=OrderTypes, ElementName=OrderUserControl}"
SelectedValue="{Binding Path=SelectedOrderType}"
SelectedValuePath="OrderTypeCode"
DisplayMemberPath="OrderTypeName" />
</Grid>
</UserControl>
public partial class OrderControl : UserControl
{
public OrderControl()
{
InitializeComponent();
OrderTypes = ...;
}
public IReadOnlyCollection<OrderTypeInfo> OrderTypes { get; private set; }
}
Also, I know I can simply create a property on the View-Model, and I get that some people would suggest that that would be the correct place to put it... but I really would like to know how I could do what I'm attempting to do if not for this scenario, maybe for other scenarios in the future?
I may be wrong but would you not need to make a dependency property on your user control for "SelectedOrderType" and bind the the View Model to that property not bind directly to the view model from the user control.
That way your UserControl is not dependent on the view model?
Edit:
I think you could set it up the way you have it, but the binding for SelectedOrderType would need to be something like {Binding Path=DataContext.SelectedOrderType, ElementName=OrderUserControl}
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 want to use a dependency property so that my label displays values selected in the Listbox. This is just to more clearly understand the working of a dependency property.
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WPFToolkit="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
xmlns:local="clr-namespace:WpfApplication1"
x:Name="MyWindow"
Height="200"
Width="300">
<StackPanel>
<ListBox x:Name="lbColor"
Width="248"
Height="56"
ItemsSource="{Binding TestColor}"/>
<StackPanel>
<Label Content="{Binding Path=Test, ElementName=lbColor}" />
</StackPanel>
</StackPanel>
</Window>
Code Behind,
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public ObservableCollection<string> TestColor { get; set; }
public String Test
{
get { return (String)GetValue(TestProperty); }
set { SetValue(TestProperty, value); }
}
// Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TestProperty =
DependencyProperty.Register("Test", typeof(String), typeof(ListBox), new UIPropertyMetadata("Test1"));
public Window1()
{
InitializeComponent();
TestColor = new ObservableCollection<string>();
DataContext = this;
TestColor.Add("Red");
TestColor.Add("Orange");
TestColor.Add("Yellow");
TestColor.Add("Green");
TestColor.Add("Blue");
}
}
}
Can anyone explain to me how will I accomplish this using a dependency property? Somehow I am very confused with the Dependency Property concept, and I just wanted to see a working example for that.
You'll need to have your ListBox "select" the current text:
<StackPanel>
<!-- Add selected item binding -->
<ListBox
x:Name="lbColor" Width="248" Height="56"
ItemsSource="{Binding TestColor}"
SelectedItem="{Binding Test}"
/>
<StackPanel>
<!-- No need for elementname - just use Test on the DataContext -->
<Label Content="{Binding Path=Test}" />
</StackPanel>
</StackPanel>
I like to think of Data Binding as Big Brother. The Binding system sets itself up to watch all of its various registered Bindings and when the proper criteria have occurred (for example, FocusLost or PropertyChanged), the Binding system copies the source value to the target. For a TwoWay or OneWayToSource binding, the Binding system will even copy from the target to the source, if the right criteria happen.
The target has to be a DependencyProperty, as this is a special kind of property that knows how to Depend on other values. What the XAML {Binding} is doing under the covers is creating a new BindingExpression and then calling BindingOperations.SetBinding, which registers a particular BindingExpression with the Binding System, so it knows how to watch and perform the updates.
The advantage of this is that neither the target nor the source needs to take the responsibility for writing code to explicitly update the other. If I have code that knows how to provide a list of Colors, why should I care how the Colors get represented to the user? Because the Binding System takes care of the binding, it doesn't matter to me if the target using my Colors is a listbox, a treeview, or any other object that knows how to handle a list of items. I can focus on what I care about (the public interface I'm exposing) and don't have to care about the messy details of gluing that interface to something else.