Setting ViewModel's Property from XAML
I have some UserControl
, It's DataContext
is binded to the ViewModel,
How to set a ViewModel's property from XAML
? 开发者_StackOverflow中文版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 controlsDataContext
property in xamlCreate 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 classViewModelBase
)
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
精彩评论