[开源]FreeSCADA的通道数据与控件属性关联以及自动刷新机制研究

【参考文章】:

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;
            }
        }

    }
}

工程界面:

实际运行界面:

原文地址:https://www.cnblogs.com/jayhust/p/5837542.html