将控制权绑定到不起作用的财产

时间:2012-03-17 23:39:14

标签: c# wpf binding textbox

我正在创建一个使用多个线程的应用程序,因此我想尝试尽可能少地在我的代码中使用UIControls。我这样做的方法是将控件绑定到我的代码后面的属性,这样我就可以通过更改该属性来更新控件,如果该属性在另一个线程上更新则无关紧要。无论如何我正在创建以下代码,以便类从我那里创建绑定。

public static class MyExtensionMethods 
{

    public static TextBoxBind<T> BindTextBox<T>(this TextBox textbox, string property=null)
    {
        return new TextBoxBind<T>(textbox,property);
    }
}



public class TextBoxBind<T> : INotifyPropertyChanged
{
    string property;

    protected T _Value;
    public T Value
    {
        get { return _Value; }
        set { _Value = value; OnPropertyChanged(property); }
    }

    public event PropertyChangedEventHandler PropertyChanged = delegate { };
    protected void OnPropertyChanged(string propertyName){
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public TextBoxBind(TextBox textbox, string property)
    {
        if (property == null)
        {
            property = "Value";
        }
        this.property = property;

        Binding b = new Binding(property)
       {
            Source = this
       };

        b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        textbox.SetBinding(TextBox.TextProperty, b);
    }
}

在我的XAML上我有:

 <TextBox  Name="textBox2"  />

因此,我将能够使用我发布的第一个代码:

        var newTextBox2 = textBox2.BindTextBox<int>();
        newTextBox2.Value = 50; // this will update the textBox2.Text = "2"
        // also every time I update the value of textBox2  newTextBox2.Value will update as well

问题是当我尝试将其绑定到自定义对象时。以此代码为例:

    public class Person 
    {
        public string Name { get; set; }
        public string Age { get; set; }

        public override string ToString()
        {
            return Age.ToString();
        }            

    }

    void LogIn_Loaded(object sender, RoutedEventArgs e)
    {
        txtUsuario.Focus();

        var newTextBox2 = textBox2.BindTextBox<Person>("Age");

        // here newTextBox2 never updates....


    }

2 个答案:

答案 0 :(得分:1)

当涉及数据绑定时,应该从运行UI的同一个线程更新对象(与CLR属性或DependencyObject无关)。如果您在代码中绑定了某个UI元素,则从单独的线程更新该元素将导致异常。但是,您始终可以检索UI线程并在那里执行属性更新。 这是一段代码,我在类似的情况下使用:

ThreadStart updateLogs = delegate()
{
    ObservableCollection<LogMessage> newLogs = this._parcer.Parce();
    foreach (LogMessage log in newLogs)
        LogMessages.Add(log);
};
App.Current.Dispatcher.BeginInvoke(updateLogs, null);

这段代码运行在一个与运行的UI不同的线程中。因此,我提取代码,实际上将绑定源(即LogMessages)更新为委托updateLogs,然后在UI线程中运行此委托,并将其传递给应用程序调度程序。

然而,如果你在不同的线程中创建单独的窗口,WPF应用程序可以有多个Dispather,尽管这种方法很少见。但为了以防万一,DependencyObject类具有Dispatcher属性,该属性引用拥有此对象的Dispather。

答案 1 :(得分:0)

OnPropertyChanged(property);应指向Value,因为那是您的Property的名称。 这不应该指向类型T。 所以这段代码不对:

if (property == null) 
{ 
  property = "Value"; 
}

因为属性应始终为"Value"

public T Value     
{     
    get { return _Value; }     
    set { _Value = value; OnPropertyChanged("Value"); }     
}