使用事件将UI元素绑定到字段时,如何防止无限递归?

Bil*_*eal 5 c# winforms

以下似乎是一个相对常见的模式(对我来说,而不是整个社区)将字符串变量绑定到TextBox的内容.

class MyBackEndClass
{
    public event EventHandler DataChanged;
    string _Data;
    public string Data
    {
        get { return _Data; }
        set
        {
            _Data = value;
            //Fire the DataChanged event
        }
    }
}

class SomeForm : // Form stuff
{
    MyBackEndClass mbe;
    TextBox someTextBox;
    SomeForm() 
    {
        someTextBox.TextChanged += HandleTextBox();
        mbe.DataChanged += HandleData();
    }

    void HandleTextBox(Object sender, EventArgs e)
    {
        mbe.Data = ((TextBox)sender).Text;
    }

    void HandleData(Object sender, EventArgs e)
    {
        someTextBox.Text = ((MyBackEndClass) sender).Data;
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是更改TextBox会触发后端数据值的更改,从而导致文本框发生更改等.这会永远运行.

有没有更好的设计模式(除了诉诸讨厌的布尔标志)正确处理这种情况?

编辑:要清楚,在实际设计中,后端类用于同步多个表单之间的更改.因此,我不能直接使用SomeTextBox.Text属性.

Billy3

Rom*_*pin 2

好吧,我已经写了一些代码,但你可能不喜欢它:)

public class DataChangedEventArgs : EventArgs
{
    public string Data { get; set; }

    public DataChangedEventArgs(string data)
    {
        Data = data;
    }
}
public delegate void DataChangedEventHander(DataChangedEventArgs e);
public class BackEnd
{
    public event DataChangedEventHander OnDataChanged;
    private string _data;
    public string Data
    {
        get { return _data; }
        set
        {
            _data = value;
            RaiseOnDataChanged();
        }
    }

    private static readonly object _sync = new object();
    private static BackEnd _instance;
    public static BackEnd Current
    {
        get
        {
            lock (_sync)
            {
                if (_instance == null)
                    _instance = new BackEnd();
                return _instance;
            }
        }
    }
    private void RaiseOnDataChanged()
    {
        if(OnDataChanged != null)
            OnDataChanged(new DataChangedEventArgs(Data));
    }
}
public class ConsumerControl
{
    public event EventHandler OnTextChanged;
    private string _text;
    public string Text
    {
        get
        {
            return _text;
        }
        set
        {
            _text = value;
            if (OnTextChanged != null)
                OnTextChanged(this, EventArgs.Empty);
        }
    }
}
public class Consumer
{
    public ConsumerControl Control { get; set; }

    public Consumer()
    {
        Control = new ConsumerControl();
        BackEnd.Current.OnDataChanged += NotifyConsumer;
        Control.OnTextChanged += OnTextBoxDataChanged;
    }

    private void OnTextBoxDataChanged(object sender, EventArgs e)
    {
        NotifyBackEnd();
    }

    private void NotifyConsumer(DataChangedEventArgs e)
    {
        Control.Text = e.Data;
    }
    private void NotifyBackEnd()
    {
        // unsubscribe
        BackEnd.Current.OnDataChanged -= NotifyConsumer;
        BackEnd.Current.Data = Control.Text;
        // subscribe again
        BackEnd.Current.OnDataChanged += NotifyConsumer;
    }
}
public class BackEndTest
{
    public void Run()
    {
        var c1 = new Consumer();
        var c2 = new Consumer();
        c1.Control.Text = "1";
        BackEnd.Current.Data = "2";
    }
}
Run Code Online (Sandbox Code Playgroud)

主要的 idia 在这里:

// unsubscribe
BackEnd.Current.OnDataChanged -= NotifyConsumer;
BackEnd.Current.Data = Control.Text;
// subscribe again
BackEnd.Current.OnDataChanged += NotifyConsumer;
Run Code Online (Sandbox Code Playgroud)