将控件绑定到属性不起作用
本文关键字:属性 不起作用 绑定 控件 | 更新日期: 2023-09-27 18:28:12
我正在创建一个使用多个线程的应用程序,因此我希望尽可能少地在代码背后使用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....
}
当涉及到数据绑定时,应该从运行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。
OnPropertyChanged(property);
应该指向Value,因为这是您的属性的名称。这不应该指向类型T
。所以这个代码是不对的:
if (property == null)
{
property = "Value";
}
因为属性应该始终是"Value"
public T Value
{
get { return _Value; }
set { _Value = value; OnPropertyChanged("Value"); }
}