【参考文章】:
1. WPF之Binding深入探讨, 地址:http://www.cnblogs.com/cappuccino/p/3251631.html
1. 几个重要的类列表:
a) Designer工程下的CommonBindingDialog.cs:
b) Designer工程下的NumericBindingPanel.cs(或者StringBindingPanel.cs):
c) CommonGUI工程下的SchemaDocument.cs(LoadSchema()和SaveSchema())和RunTime工程下的ShemaView.cs(LoadDocument()):
分别实现WPF界面的XMAL文件方式存储和XMAL文件方式载入,和实现WinForm下的WPF界面的载入。
2. 通道数据与控件属性关联(以及自动刷新机制):
a) 通道数据与控件属性绑定:
CommonBindingDialog.cs中的事件响应方法(Create association按钮被按下):
private void CreateAssociationButton_Click(object sender, EventArgs e) { SavePanelStateAndClose(); if (propertyList.SelectedIndex >= 0 && bindingTypes.SelectedIndex >= 0) { BaseBindingPanelFactory factory = (BaseBindingPanelFactory)bindingTypes.SelectedItem; // factory在这里执行过后,就是NumericBindingPanel.cs里定义的NumericBindingPanelFactory类型了 bindingPanel = factory.CreateInstance(); // bindingPanel的具体类型是NumericBindingPanel还是StringBindingPanel,在这里得到了重新定义(不再是基类的BaseBindingPanel类型了) bindingPanel.Initialize(element, propertyList.SelectedItem as PropertyWrapper, null); bindingPanel.Parent = panel1; bindingPanel.Dock = DockStyle.Fill; CreateAssociationButton.Enabled = false; bindingTypes.Enabled = false; } }
CommonBindingDialog.cs中的事件响应方法(Save按钮被按下):
private void saveButton_Click(object sender, EventArgs e) { SavePanelStateAndClose(); if (activeBindings.Count > 0) { foreach (PropertyWrapper key in activeBindings.Keys) { DependencyObject depObj; DependencyProperty depProp; System.Windows.Data.BindingBase binding = activeBindings[key]; if (key.GetWpfObjects(out depObj, out depProp) && binding != null) BindingOperations.SetBinding(depObj, depProp, binding); } } DialogResult = DialogResult.OK; Close(); }
继续来看SavePanelStateAndClose方法的实现:
private void SavePanelStateAndClose() { if (bindingPanel != null) { BindingBase binding = bindingPanel.Save(); // 见NumericBindingPanel类的Save()定义 if (binding != null) activeBindings[bindingPanel.Property] = binding; // activeBindings为Dictionary<PropertyWrapper, BindingBase>,bindingPanel.Property为PropertyWrapper bindingPanel.Dispose(); bindingPanel = null; } }
我们再继续深入NumericBindingPanel.cs里面定义的Save方法:
public override System.Windows.Data.BindingBase Save() { if (channel != null) { System.Windows.Data.Binding bind = new System.Windows.Data.Binding("Value"); ChannelDataProvider cdp = new ChannelDataProvider(); cdp.ChannelName = channel.PluginId + "." + channel.Name; bind.Source = cdp; // 绑定的源数据为通道数据 bind.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; cdp.Refresh(); ComposingConverter conv = new ComposingConverter(); if (checkBox1.Checked) { RangeConverter rc = new RangeConverter(); rc.Min = Decimal.ToDouble(minEdit.Value); rc.Max = Decimal.ToDouble(maxEdit.Value); conv.Converters.Add(rc); } conv.Converters.Add(new Kent.Boogaart.Converters.TypeConverter(cdp.Channel.Type, Property.PropertyType)); bind.Converter = conv; bind.Mode = BindingMode.TwoWay; DependencyObject depObj; DependencyProperty depProp; if (Property.GetWpfObjects(out depObj, out depProp)) bind.FallbackValue = depObj.GetValue(depProp); return bind; } else return base.Save(); }
这里关键是WPF编程方式下System.Windows.Data.Binding类的使用,下面我们来看一个简单的WPF示例工程,该工程演示了WPF中一个TextBox的Text属性与
数据源的绑定、以及子线程中绑定数据源值更新的自动同步:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Threading; using System.ComponentModel; namespace WpfApplication1 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public class DataSource : INotifyPropertyChanged { private int _index; public int Index { get { return _index; } set { _index = value; if (PropertyChanged != null) { this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Index")); } } } public event PropertyChangedEventHandler PropertyChanged; } System.Windows.Data.Binding _bind; Thread _thread; DataSource _dataSource; bool _run; public MainWindow() { InitializeComponent(); _dataSource = new DataSource(); // System.Windows.Data.Binding方式 _bind = new System.Windows.Data.Binding(); _bind.Source = _dataSource; _bind.Path = new PropertyPath("Index"); _bind.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; this.textBox1.SetBinding(TextBox.TextProperty, _bind); _run = true; _thread = new Thread(Test); _thread.Start(); } void Test() { while (_run) // 里面不能放阻塞式的方法,否则逻辑可能一直卡住 { _dataSource.Index++; Thread.Sleep(100); } } private void Window_Closing(object sender, CancelEventArgs e) { _run = false; if (_thread != null) { _thread.Join(); _thread = null; } } } }
工程界面:
实际运行界面: