WPF Learning (2)-binding and wpf learning binding
Binding, this looks amazing. It is very difficult for me to understand it.
The core idea of WPF binding is that changes in the attribute values of the data layer can be reflected to the display layer, and vice versa, and the response process can be separated.
Traditional Winform programming is more primitive, and there are not so many hidden (implicate) technologies. I will understand the WPF mechanism through the implementation of winform.
Public class DataLayer {public delegate void TextChangedEventHandler (object sender, EventArgs e); public event TextChangedEventHandler TextChanged; private string text = ""; public string Text {get {return text ;} set {if (text! = Value) {text = value; if (this. TextChanged! = Null) this. TextChanged (this, new EventArgs ());}}}}Data Layer Code public partial class PresentationLayer: Form {TextBox ui = new TextBox (); DataLayer data = new DataLayer (); public PresentationLayer () {InitializeComponent (); this. controls. add (ui); ui. textChanged + = new System. eventHandler (this. presentationLayerTextChanged); data. textChanged + = new DataLayer. textChangedEventHandler (this. dataLayerTextChanged);} private void PresentationLayerTextChanged (object sender, EventArgs e) {data. text = ui. text;} private void DataLayerTextChanged (object sender, EventArgs e) {ui. text = data. text ;}}Display Layer Code
In this way, data is synchronized between the front and back ends. There are three disadvantages:
1. Data Synchronization for each attribute has a single function and the same content. There is no need to define event Delegation for each attribute RESPONSE event at the data layer.
2. To maintain data synchronization, you need to write a large amount of data synchronization code at the presentation layer. If there are many attributes, the repetitive workload is very large.
3. As a member of PresentationLayer, data increases coupling. The data layer and the presentation layer are not completely separated.
Problem 1 is well solved. An interface event is abstracted from the data layer and the attribute name of the event to be stimulated must be specified in the event parameters.
Public interface INotifyPropertyChanged {event inclupropertychanged;} public delegate void updated (object sender, PropertyChangedEventArgs e); public class updated: EventArgs {private readonly string propertyName; public PropertyChangedEventArgs (string propertyName) {this. propertyName = propertyName;} public virtual string PropertyName {get {return this. propertyName ;}}}Abstract interface events
In this way, the original DataLayer becomes like this.
Public class DataLayerExt: INotifyPropertyChanged {public event PropertyChangedEventHandler PropertyChanged; private string text = ""; public string Text {get {return text;} set {if (text! = Value) {text = value; if (this. PropertyChanged! = Null) this. PropertyChanged (this, new PropertyChangedEventArgs ("Text "));}}}}DataLayerExt
Problem 2 is logically not difficult to solve. Define a static method. The parameters of the method should indicate which two properties of the two objects need to be synchronized, and record the synchronization relationship.
Public class BindingOperations {static List <BindingRelative> lstBindingRelative = new List <BindingRelative> (); // The Source and target types should be objects. This is just a semantic representation. It is very difficult to fully implement public static void SetBinding (TextBox uiObject, string uiPropertyName, DataLayerExt dataObject, string dataPropertyName) {// use the list to record the synchronization relationship lstBindingRelative. add (new BindingRelative () {UIObject = uiObject, UIObjectPropertyName = uiPropertyName, DataObject = dataObject, DataObjectPropertyName = dataPropertyName}); // Add the event processing method uiObject. textChanged + = new EventHandler (uiObject_TextChanged); dataObject. propertyChanged + = new PropertyChangedEventHandler (target_PropertyChanged);} static void uiObject_TextChanged (object sender, EventArgs e) {foreach (BindingRelative item in lstBindingRelative) {if (item. UIObjectPropertyName = "Text") {// the general method should be like this // item. source. sourcePropertyName = item. target. dataPropertyName; item. dataObject. text = item. UIObject. text; break ;}} static void target_PropertyChanged (object sender, PropertyChangedEventArgs e) {foreach (BindingRelative item in lstBindingRelative) {if (item. dataObjectPropertyName = e. propertyName) {// the general method should be like this // item. source. sourcePropertyName = item. target. dataPropertyName; item. UIObject. text = item. dataObject. text; break ;}}}// defines a public class BindingRelative {public TextBox UIObject; public string UIObjectPropertyName; public DataLayerExt DataObject; public string DataObjectPropertyName ;}Create a Data Synchronization relationship
In this way, the presentation layer only needs to design the style of the interface, define the display elements in the interface, and completely separate from the background data. Unconsciously, problem 1 is also resolved.
Public partial class PresentationLayerExt: Form {public TextBox ui = new TextBox (); public PresentationLayerExt () {InitializeComponent (); this. Controls. Add (ui );}}PresentationLayerExt
Of course, to specify the synchronization relationship, you still need to implement it using code, but not in the presentation layer, but outside, such as in the Main () function.
Static class Program {// <summary> // main entry point of the application. /// </Summary> [STAThread] static void Main () {Application. enableVisualStyles (); Application. setCompatibleTextRenderingDefault (false); PresentationLayerExt p = new PresentationLayerExt (); DataLayerExt d = new DataLayerExt (); BindingOperations. setBinding (p. ui, "Text", d, "Text"); Application. run (p );}}Main ()
Above, we use Winform to implement data synchronization and separate the data layer from the presentation layer. In Winform, it is very difficult to obtain the attributes of an object based on the attribute name string. The SetBinding method for defining synchronization relations has many drawbacks and is almost no universal. However, this does not prevent the running mechanism of the WPF binding technology from being understood through the Winform example.
The binding technology of WPF achieves the same principle of data synchronization between the data layer and the display layer:
The classes at the data layer must be derived from the INotifyPropertyChanged interface in System. ComponentModel,
Each class must contain the PropertyChanged event. When the property value changes, this event is triggered. The attribute name is input in the event parameter.
The data synchronization relationship is established by the SetBinding method of BindingOperations.
In WPF, the last two parameters of the SetBinding method are packaged as Binding objects.
In this way, the object parameters of the SetBinding method can use the most primitive DependencyObject type object to improve universality.
Many WPF controls have encapsulated the SetBinding method, so that when the object is bound to its own property, you can call its own SetBinding method to omit the target parameter.
A complete example of Binding technology for WPF applications
// Data, as the source of the bound Data, will always receive changes to the bound target // However, If You Want To Tell The bound target of the Data source change, // You must derive from the INotifyPropertyChanged interface, public class DataClass: System. componentModel. INotifyPropertyChanged {private string myString; public string MyString {get {return myString;} set {myString = value; // triggers the event if (PropertyChanged! = Null) PropertyChanged (this, new System. ComponentModel. PropertyChangedEventArgs ("MyString") ;}} public event System. ComponentModel. PropertyChangedEventHandler PropertyChanged ;}Define data class
// As the bound target class, the class must be derived from DependencyObject // This defined class can meet the type requirements of the first parameter of the SetBinding method // an additional dependency attribute must be defined, used to meet the second parameter requirements of the SetBinding method // use the DependencyObject derived Methods GetValue and SetValue to control the storage of attributes and take public class UIClass: System. windows. dependencyObject {public string MyText {get {return (string) GetValue (MyTextProperty);} set {SetValue (MyTextProperty, value) ;}} public static readonly System. windows. dependencyProperty MyTextProperty = System. windows. dependencyProperty. register ("MyText", typeof (string), typeof (UIClass ));}Display type
Test class
Compared with Winform, WPF implements the function of saving/retrieving object attributes by attribute name, and calls this technology dependency attribute.
With the dependency attribute, the SetBinding method of WPF is truly universal. This technology will be further studied later.
What's amazing about the world of programs? Some people do more work and the results look amazing.
The so-called data and display separation, but in addition to the two layers, an additional management organization is created.
The binding technology of WPF is a department in this management organization, responsible for receiving and sending express parcels!