【问题标题】:Notifying change of a calculated databound property in WPF通知 WPF 中计算的数据绑定属性的更改
【发布时间】:2015-05-16 02:15:36
【问题描述】:

作为练习,我决定在 WPF 中创建一个自行车齿轮计算器。我使用触发OnPropertyChanged() 的setter 创建了两个私有字段,但我有一个数据绑定属性ratio,它表现为“只读”,因为它是动态计算的。当我运行程序时,文本框显示,初始值正确显示,属性更改处理程序中的“工作”字被显示,但ratio TextBlock 没有更新。

我怀疑这是由于“获取”属性的方式,我想知道是否绝对有必要为每个添加一个私有字段,我想知道这是否应该有任何 DependencyProperty ......但实际上我已达到我对此的知识极限,无法让这个琐碎的程序运行。


这是我的模型:

class SingleGearsetModel : INotifyPropertyChanged
{
    public SingleGearsetModel()
    {
        crank = 44;
        cog = 16;
    }

    private int _crank;
    private int _cog;

    public int crank { 
        get{return _crank;}
        set{
            _crank = value;
            OnPropertyChanged("crank");
        }
    }

    public int cog {
        get{return _cog;}
        set{
            _cog = value;
            OnPropertyChanged("cog");
        } 
    }

    public double ratio
    {
        get {
            return (double)crank / (double)cog;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string arg)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(arg));
            Console.Writeline("working");
        }
    }

} // end class

这是我的 XAML:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="CalculadorFixaWPF.MainWindow"
    x:Name="Window"
    Title="MainWindow"
    Width="640" Height="480">

    <DockPanel x:Name="LayoutRoot">
            <TextBox Text="{Binding crank, Mode=TwoWay}"/>
            <TextBox Text="{Binding cog, Mode=TwoWay}"/>
            <TextBlock Text="{Binding ratio, StringFormat={}{0:0.00}}"/>
    </DockPanel>
</Window>

这是在我的代码隐藏 (MainWindow.xaml.cs) 中:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();
        this.DataContext = new SingleGearsetModel();
    }
}

感谢阅读!

【问题讨论】:

    标签: wpf data-binding notifications


    【解决方案1】:

    由于比率是一个计算字段,因此您希望在每次值可能发生变化时添加通知。如果crankcog 发生更改,就会发生这种情况。

    所以,在您通知他们被更改后,还要通知ratio 已更改:

    public int crank 
    { 
        get{return _crank;}
        set{
            _crank = value;
            OnPropertyChanged("crank");
    
            // *** Notify that ratio has also been changed ***
            OnPropertyChanged("ratio");
        }
    }
    

    cog 也是如此。

    编辑: 根据您的 cmets,您可以通过以下方式在班级内部注册 PropertyChanged 事件并为比率引发 PropertyChanged:

    // Constructor
    public SingleGearsetModel()
    {
        ....
       PropertyChanged += SingleGearsetModel_PropertyChanged;
    }
    
    // PropertyChanged event handler
    void SingleGearsetModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
            if (e.PropertyName == "cog" || e.PropertyName == "crank")
            {
                OnPropertyChanged("ratio");
            }
    }
    

    使用这种方法,您无需在属性的设置器中添加OnPropertyChanged("ratio") - 每当它们被引发时,您都会获得事件(在SingleGearsetModel_PropertyChanged 中)并引发OnPropertyChanged("ratio")

    【讨论】:

    • 不错!只是为了完整起见,假设我有一些类似于“Excel”电子表格的东西,其中只有几个值(属性)是明确的,而更多的只是计算出来的。我已经看到一些 javascript 代码具有一些“刷新()”或​​“更新()”函数来重新计算所有内容,在过程中设置私有字段,但这在数据绑定的情况下听起来不优雅。您是否认为您的最后一种方法可以用于处理大量计算值(没有 setter,只有 getter),而无需大量容易出错、重复的“通知程序”代码?
    • 简短答案 - 视情况而定 :) 长答案:对于具有大量这些“计算字段”和少量实际值的 Excel 电子表格,可能会使用不同的方法(比如每个计算字段更聪明,它知道它依赖于谁,因此会为自己触发 propertychanged)。但是 Excel 电子表格完全不同,因此可能不是一个很好的比较。在大多数标准情况下,这个解决方案已经足够了——即使你有更多的逻辑而不是单个 if 语句。
    • 好的,我认为这解决了像这样的简单项目的问题,并且您为更大的项目指出了一个明智的方向。感谢您的关注!
    【解决方案2】:

    最简单的方法是将OnPropertyChanged("ratio") 添加到crankcog 的设置器中。您可以执行更复杂的操作,例如从 crankcog 监听 OnPropertyChanged 事件,并在其中任何一个发生变化时自动触发 OnPropertyChanged("ratio"),但这至少可以让您继续前进。

    【讨论】:

    • 您能否建议一些方法(代码?)来实现您提到的第二个选项(触发 ratio 从曲柄或齿轮更改而无需重复代码)?
    • ratio“听”到cogcrank 会很有趣,所以我可以(将来)让development_metersratio 和@987654334 @、speeddevelopment_meterscadence_RPM等等,而不是大量重复代码)
    猜你喜欢
    • 2013-08-16
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-23
    相关资源
    最近更新 更多