我有一个自定义的UserControl,继承自RichTextBox。这个类有一个依赖属性Equation,可以进行双向绑定。
当用户将项目拖放到控件上时,我会更改Equation。这会将更改正确地传播到绑定的另一端,从而触发属性更改通知,但UI不会更改。如果我将绑定更改为不同的对象,然后再次绑定回来,它就会显示更新后的Equation。
如何在不更改绑定的情况下强制刷新?现在我正在设置Equation=null,然后再重新设置,这样可以起作用,但似乎有些hackish。肯定有更优雅的方法。
以下是控件的相关部分。我希望在更改Equation(Equation.Components.Add(txt))之后调用OnEquationChanged回调函数。
当用户将项目拖放到控件上时,我会更改Equation。这会将更改正确地传播到绑定的另一端,从而触发属性更改通知,但UI不会更改。如果我将绑定更改为不同的对象,然后再次绑定回来,它就会显示更新后的Equation。
如何在不更改绑定的情况下强制刷新?现在我正在设置Equation=null,然后再重新设置,这样可以起作用,但似乎有些hackish。肯定有更优雅的方法。
以下是控件的相关部分。我希望在更改Equation(Equation.Components.Add(txt))之后调用OnEquationChanged回调函数。
public class EquationTextBox : RichTextBox
{
protected override void OnDrop(DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.StringFormat))
{
string str = (string)e.Data.GetData(DataFormats.StringFormat);
EquationText txt = new EquationText(str);
//// Preferred /////
Equation.Components.Add(txt);
//// HACK /////
Equation eqn = this.Equation;
eqn.Components.Add(txt);
this.Equation = null;
this.Equation = eqn;
///////////////
Console.WriteLine("Dropping " + str);
}
}
public Equation Equation
{
get { return (Equation)GetValue(EquationProperty); }
set { SetValue(EquationProperty, value); }
}
private static void onEquationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
string prop = e.Property.ToString();
EquationTextBox txtBox = d as EquationTextBox;
if(txtBox == null || txtBox.Equation == null)
return;
FlowDocument doc = txtBox.Document;
doc.Blocks.Clear();
doc.Blocks.Add(new Paragraph(new Run(txtBox.Equation.ToString())));
}
public static readonly DependencyProperty EquationProperty =
DependencyProperty.Register("Equation",
typeof(Equation),
typeof(EquationTextBox),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(onEquationChanged)));
private bool mIsTextChanged;
}
这是双向绑定中的另一个端点属性。由于Equation.Components.Add(txt)调用,上述代码会触发equation_PropertyChanged事件。
public Equation Equation
{
get{ return mEquation; }
set { mEquation = value; NotifyPropertyChanged(); }
}
private void equation_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
NotifyPropertyChanged("Equation");
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
编辑 --------------------------
根据评论,我尝试使用此调度程序(请注意,这是我第一次尝试使用调度程序):
string str = (string)e.Data.GetData(DataFormats.StringFormat);
EquationText txt = new EquationText(str);
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
Equation.Components.Add(txt);
NotifyPropertyChanged("Equation");
}));
但仍然没有UI更新。
编辑2 --------------------------
双向绑定是在XAML中完成的。
<l:EquationTextBox x:Name="ui_txtVariableEquation" Grid.Row="0" Grid.Column="2"
Grid.RowSpan="3" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
AllowDrop="True"
Equation="{Binding SelectedVariableVM.Variable.Equation, Mode=TwoWay}">
</l:EquationTextBox>
与Equation类中的Components对象相关的信息
public class Equation : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Equation()
{
mComponents = new ObservableCollection<EquationComponent>();
mComponents.CollectionChanged += new NotifyCollectionChangedEventHandler(components_CollectionChanged);
}
public Equation(string eqn) : this()
{
mComponents.Add(new EquationText(eqn));
}
public ObservableCollection<EquationComponent> Components
{
get{ return mComponents; }
set{ mComponents = value; NotifyPropertyChanged();}
}
public override string ToString()
{
string str = "";
for(int i=0; i<mComponents.Count; i++)
str += mComponents[i].ToString();
return str;
}
private void components_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
NotifyPropertyChanged("Components");
}
private ObservableCollection<EquationComponent> mComponents;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Variable : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Variable(string name = "var", VariableType type = VariableType.UnknownType) :
this(name, "", 0, type)
{
}
并且...
public class Variable : INotifyPropertyChanged
{
public Variable(string name, string unit, object val, VariableType type)
{
mEquation = new Equation(name + " = " + val.ToString() +
mEquation.PropertyChanged += new PropertyChangedEventHandler(equation_PropertyChanged);
}
...
public Equation Equation
{
get{ return mEquation; }
set { mEquation = value; NotifyPropertyChanged(); }
}
private void equation_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
NotifyPropertyChanged("Equation");
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private Equation mEquation;
...
}
当Equation类中触发事件时,会调用Variable.equation_PropertyChanged方法。
INotifyPropertyChanged
接口。我有一个同事因为他实现了PropertyChanged
事件但忘记在类签名中添加接口而花费数小时调试数据绑定问题。 - Mike Strobel