WPF learning 07: Data Binding of MVVM preparation knowledge, wpfmvvm
MVVM is a mode, while WPF's data binding mechanism is a function set built in WPF, which is irrelevant to the two.
However, with the help of various built-in functional sets of WPF, such as data binding, commands, and data templates, We can efficiently implement MVVM on WPF. Therefore, we need to understand the various MVVM-related WPF built-in feature sets to learn and practice MVVM on a solid basis.
This article is a follow-up of WPF 03: Element Binding. It will show three key points for data Binding: DataContext INotifyPropertyChanged IValueConverter
MVVM Introduction
MVVM divides the User Interface into three parts: View, Model, and View Model.
The three parts are divided as follows:
View: interface code and complete data visualization.
Model: A series of classes that we interact with the business layer.
View Model: 1. Convert the part to be displayed in the Model to View-friendly data. 2. Manage the interaction between views.
As shown in the dependency relationship, V depends on the VM, and vice versa. The VM depends on M, and vice versa.
After understanding data binding, commands, and data templates, we will return to explain MVVM again.
DataContext
In WPF learning 03: Element Binding, we only studied how to implement data Binding between controls. If ElementName is not specified, Binding will be neither set between Source nor RelativeSource, first-level query for DataContext until it is found.
Example:
<StackPanel HorizontalAlignment = "Center" TextBlock. Foreground = "# 019AFF" DataContext = "{x: Static Colors. White}"> <! -- Specify Path, an attribute of the bound object --> <TextBlock Text = "{Binding Path = R}"> </TextBlock> <TextBlock Text = "{Binding Path = G}"> </TextBlock> <TextBlock Text = "{Binding Path = B}"> </TextBlock> <! -- Bind the entire object without specifying the Path --> <TextBlock Text = "{Binding}"> </TextBlock> </StackPanel>
In common cases, we set DataContext to the top-level element, which is generally a Window.
We can configure DataContext in the background code:
public class Person{ private Int32 _age; public Int32 Age { get { return _age; } set { _age = value; } } private String _name; public String Name { get { return _name; } set { _name = value; } }}private void Window_Loaded(object sender, RoutedEventArgs e){ person = new Person() { Name = "Kenny", Age = 30 }; this.DataContext = person;}private void Button_Click(object sender, RoutedEventArgs e){ person.Name = "John Locke"; person.Age = 40;}
Changes made in XAML:
<StackPanel HorizontalAlignment="Center" TextBlock.Foreground="#019AFF"> <TextBlock Text="{Binding Path=Name}"></TextBlock> <TextBlock Text="{Binding Path=Age}"></TextBlock> <Button Click="Button_Click">Click me</Button></StackPanel>
The effect is as follows:
We can see that the expected value is indeed displayed, but if you click the button, you will not see any changes. Next we will explain the cause and solution.
INotifyPropertyChanged
In the built-in data binding mechanism of WPF, Dependency Property can establish data binding relationships without any additional configuration. All the attributes of self-built WPF controls are packaged by the traditional. Net attributes.
If we want to set the data binding source as the property of our Defined Object and this property is not a Dependency Property, we only need to implement the INotifyPropertyChanged interface, the PropertyChanged event is called when the corresponding attribute changes to notify the target element.
We will make the following changes to the background code:
public class Person : INotifyPropertyChanged{ public event PropertyChangedEventHandler PropertyChanged;
private Int32 _age; public Int32 Age { get { return _age; } set { _age = value; if (PropertyChanged != null) PropertyChanged.Invoke(this,new PropertyChangedEventArgs("Age")); } } private String _name; public String Name { get { return _name; } set { _name = value; if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name")); } }}
The effect is as follows:
IValueConverter
In some special cases, the source and target attributes cannot be connected and need to be converted. In this case, ValueConverter must be used. For example:
Data Binding is performed based on age, and the text is displayed in the same color. effect:
XAML code:
<TextBlock Text="{Binding Path=Name}"></TextBlock><TextBlock Name="AgeTextBlock" Text="{Binding Path=Age}"><TextBlock.Foreground> <Binding Path="Age"> <Binding.Converter> <local:TextBlockColorValueConverter></local:TextBlockColorValueConverter> </Binding.Converter> </Binding></TextBlock.Foreground></TextBlock>
Background code:
[ValueConversion (typeof (Boolean), typeof (Int32)] public class TextBlockColorValueConverter: IValueConverter {public object Convert (object value, Type targetType, object parameter, System. globalization. cultureInfo culture) {if (int) value <18) return new SolidColorBrush (Colors. violet); else return new SolidColorBrush (Colors. red);} // if no data is returned from the target, null public object ConvertBack (object value, Type targetType, object parameter, System. globalization. cultureInfo culture) {return null ;}}
Data Binding background code implementation
Previously, data binding was implemented using XAML. Here we provide the background code to implement data binding. The following example is implemented:
First, place a Name on the two controls and remove all the previously bound code:
<TextBlock Name="NameTextBlock"></TextBlock><TextBlock Name="AgeTextBlock"></TextBlock>
Background code:
var bind = new Binding("Name"){ Source = person,};NameTextBlock.SetBinding(TextBlock.TextProperty, bind);bind = new Binding("Age"){ Source = person,};AgeTextBlock.SetBinding(TextBlock.TextProperty, bind);bind = new Binding("Age"){ Source = person, Converter = new TextBlockColorValueConverter()};AgeTextBlock.SetBinding(TextBlock.ForegroundProperty, bind);
The effect is the same as before.