wpf 手动触发依赖属性刷新

标签 wpf dependency-properties

我有一个来自 RichTextBox 的自定义 UserControl 子类。此类具有双向绑定(bind)的依赖属性 Equation。

当用户将一个项目放到控件上时,我会更改 Equation。这会将更改正确传播到绑定(bind)的另一端,从而触发属性更改通知,但 UI 没有更改。如果我将绑定(bind)更改为不同的对象并返回,则它会显示更新后的方程式。

如何在不更改绑定(bind)的情况下强制刷新?现在我正在设置 Equation=null 然后返回它有效,但这似乎很老套。一定有更优雅的东西。

这里是控件的相关部分。我希望在更改方程 (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;
}

这是双向绑定(bind)另一端的属性。作为 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 --------------------------

双向绑定(bind)在 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>

与 Components 对象相关的信息(在 Equation 类中)

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

最佳答案

我认为问题在于绑定(bind)产生的值实际上并未改变(它仍然是相同的Equation 对象)。如果 DP 值没有改变,则不会调用您的 DP 更改处理程序。

或许,在您的 DP 更改处理程序中,您应该订阅新方程式的 PropertyChanged 事件,然后在基础属性更改时重建您的文档:

private static void onEquationChanged(
    DependencyObject d,
    DependencyPropertyChangedEventArgs e)
{
    var txtBox = d as EquationTextBox;
    if (txtBox == null)
        return;

    var oldEquation = e.OldValue as Equation;
    if (oldEquation != null)
        oldEquation.PropertyChanged -= txtBox.OnEquationPropertyChanged;

    var newEquation = e.NewValue as Equation;
    if (newEquation != null)
        newEquation.PropertyChanged += txtBox.OnEquationPropertyChanged;

    txtBox.RebuildDocument();
}

private void OnEquationPropertyChanged(object sender, EventArgs e)
{
    RebuildDocument();
}

private void RebuildDocument()
{
    FlowDocument doc = this.Document;

    doc.Blocks.Clear();

    var equation = this.Equation;
    if (equation != null)
        doc.Blocks.Add(new Paragraph(new Run(equation.ToString())));
}

关于wpf 手动触发依赖属性刷新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23745837/

相关文章:

c# - xamDataGrid 过滤器记录样式

.net - 为什么在绑定(bind)到它时没有设置我的依赖属性?

c# - 集合依赖属性

c# - 处置或终止 DispatcherTimer 对象和访问 DispatcherTimer 对象

wpf - 自定义依赖属性仅触发一次

c# - 在 ViewModel 中访问 DependencyPropertyValue

c# - 从不同线程读取 DependencyProperty

wpf - 在 Visual Studio 设计器中隐藏 WPF 元素

功能区控件的 WPF 数据绑定(bind)

wpf - WPF 中的数据绑定(bind)单选按钮列表