数据绑定和跨线程异常

本文关键字:异常 线程 数据绑定 | 更新日期: 2023-09-27 18:05:19

试图弄清楚这个代码中的缺陷:

场景1:此场景使用数据绑定,并在PriceSimulator类的NotifyPropertyChanged()方法中导致众所周知的跨线程异常

场景2:这个场景通过订阅PriceSimulatorPropertyChanged事件解决了这个问题,消除了跨线程问题,但必须完全避免数据绑定。

假设场景1是预期的场景,假设一个人不知道PriceSimulator的内部工作原理,只是想绑定到Price属性,这里的核心问题是什么?

Form1.cs:

public partial class Form1 : Form
{
    PriceSimulator simul;
    Action labelAction;
    public Form1()
    {
        InitializeComponent();
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        labelAction = new Action(SetLabel);
        simul = new PriceSimulator(5, 1000);
        //Scenario 1:
        //Use data binding and get Cross-Thread exception
        //label1.DataBindings.Add("Text", simul, "Price");
        //Scenario 2:
        //This works fine
        //Subscribe to PropertyChanged event
        simul.PropertyChanged += task_PropertyChanged;
        simul.Start();
    }
    //Scenario 2:
    void task_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (label1.InvokeRequired)
            Invoke(labelAction);
        else SetLabel();
    }
    private void SetLabel()
    {
        label1.Text = simul.Price.ToString("C2"); 
    }
}

PriceSimulator.cs:

public class PriceSimulator : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged; 
    private int max, delay, priceValue;
    private Timer timer;
    public PriceSimulator(int max, int delay)
    {
        this.max = max;
        this.delay = delay;
    }
    public void Start()
    {
        timer = new Timer(CallbackProc, null, delay, delay);
    }
    private void CallbackProc(object obj)
    {
        if (++Price >= max)
            timer.Dispose();
    }
    private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        try
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        catch (Exception ex)
        {
            timer.Dispose();
            System.Windows.Forms.MessageBox.Show(ex.Message);
        }
    }
    public int Price 
    {
        get
        {
            return priceValue;
        }
        set
        {
            if (priceValue != value)
            {
                priceValue = value;
                NotifyPropertyChanged();
            }
        }
    }
}

数据绑定和跨线程异常

你必须在你的pricessimulator类中有当前上下文:

private readonly SynchronizationContext _context = SynchronizationContext.Current;

现在你有了上下文,你可以用它来更新UI:

 _context.Post(delegate
                {
                    if (++Price >= max)
                       timer.Dispose();
                }, null);