【问题标题】:Calculated field not updating until edited in UI计算字段在 UI 中编辑之前不会更新
【发布时间】:2019-06-16 23:46:23
【问题描述】:

作为新手程序员,我正在尝试使用 XAML 和 C# 测试数据绑定。我有两个绑定到属性的滑块,我想用滑块设置的两个属性值的总和来更新一个 TextBox。

我正在使用INotifyPropertyChanged 并尝试更改我能找到的每个属性,但我无法让文本框更新,直到我编辑文本框,此时文本框更新为正确的值。使用UpdateSourceTrigger=PropertyChanged 只会在我编辑文本框时更新文本框,而不是在我选择另一个元素时。我尝试编写一个单独的事件处理程序,它不使用[CallerNameMember] 并使用指定的属性,但它似乎没有改变任何东西。

<Grid>
    <Grid.RowDefinitions>

    </Grid.RowDefinitions>

    <TextBox Grid.Row="0"
             Text="{Binding BoundNumber, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
             FontSize="20"
             FontWeight="Bold"
             AllowDrop="False" />

    <Slider Grid.Row="1"
            Value="{Binding BoundNumber, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
            Maximum="100"
            Minimum="10"
            IsSnapToTickEnabled="True"
            TickFrequency="10" />
    <TextBox Grid.Row="2"
             Text="{Binding BoundNumber2, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
             AllowDrop="False" />
    <Slider Grid.Row="3"

            Value="{Binding BoundNumber2, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
            Maximum="100"
            Minimum="10"
            IsSnapToTickEnabled="True"
            TickFrequency="10" />


    <TextBox Grid.Row="4"
            Name="MathBox"
             Text="{Binding QuickMath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}">
           </TextBox>

</Grid>

public partial class OrderScreen : INotifyPropertyChanged
{
    public OrderScreen()
    {
        DataContext = this;

        InitializeComponent();
     }

    private int quickMath;
    public int QuickMath
    {
        get { return _boundNumber + _boundNumber2; }
        set
        {

            if (value != quickMath)
            {
                quickMath = value;
                OnPropertyChanged();

            }
        }
    }
    private int _boundNumber;
    public int BoundNumber
    {
        get { return _boundNumber; }
        set
        {
            if (_boundNumber != value)
            {
                _boundNumber = value;
               // MathBox.Text = quickMath.ToString();
                OnPropertyChanged();

            }
        }
    }

    private int _boundNumber2;
    public int BoundNumber2
    {
        get { return _boundNumber2; }
        set
        {
            if (_boundNumber2 != value)
            {
                _boundNumber2 = value;
                MathBox.Text = quickMath.ToString();
                OnPropertyChanged();

            }
        }
    }

 public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {

        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

我可以让它与注释掉的MathBox.Text = quickMath.ToString(); 一起工作,但我希望有更好的方法来处理数据绑定。感谢期待!

【问题讨论】:

    标签: c# wpf xaml inotifypropertychanged


    【解决方案1】:

    绑定机制订阅DataSource 对象的PropertyChanged 事件,因此无需将事件与INPC 实现一起“初始化”,但您可能已经注意到,PropertyChanged 事件用于QuickMath 属性确实不会在 BoundNumberBoundNumber2 更改时触发。

    您可以通过不同的方式修复它,例如为所有受影响的属性显式调用 OnPropertyChanged:

    private int _boundNumber;
    public int BoundNumber
    {
        get { return _boundNumber; }
        set
        {
            if (_boundNumber != value)
            {
                _boundNumber = value;
                OnPropertyChanged();
                OnPropertyChanged(nameof(QuickMath));
            }
        }
    }
    

    请注意,这样您可以将QuickMath 属性保持为只读。这种方法在其他情况下效果很好,例如与时间相关的属性,例如,如果您的数据源属性根据记录的时间戳和当前时间格式化字符串,如 "Edited 2 minutes ago",然后您调用 @ 987654330@ 作为定时任务。

    public int QuickMath => _boundNumber + _boundNumber2;
    

    或者,您可以更新QuickMath,同时修改BoundNumberBoundNumber2 以触发OnPropertyChanged()QuickMath setter 内部调用:

    private int _boundNumber2;
    public int BoundNumber2
    {
        get { return _boundNumber2; }
        set
        {
            if (_boundNumber2 != value)
            {
                _boundNumber2 = value;
                OnPropertyChanged();
                QuickMath = BoundNumber + BoundNumber2;
            }
        }
    }
    

    如果QuickMath 中的逻辑不允许将其设为只读属性,则这是有道理的。在这种情况下,您必须相应地调整 getter 并在那里使用私有或受保护的 setter 以避免数据不一致和意外行为。

    private int _quickMath;
    public int QuickMath
    {
        get { return _quickMath; }
        private set
        {
            if (value != _quickMath)
            {
                _quickMath = value;
                OnPropertyChanged();
            }
        }
    }
    

    在这两种情况下,都不需要双向绑定到QuickMath

    <TextBlock Grid.Row="4" Text="{Binding QuickMath, Mode=OneWay}"/>
    

    在旁注中并查看其余代码,确实值得一提的是,绑定机制有望将 UI 与数据隔离,其中 XAML 知道数据源对象属性(名称和类型),但不知道它是内部实现,而数据源对象可能根本不了解 XAML。所以

    1. 不应从数据对象调用FrameworkElements,如MathBox.Text
    2. 将数据对象类与页面或控件类完全分开是一种很好的设计。

    希望这会有所帮助。

    【讨论】:

    • 这行得通!我之前使用的是OnPropertyChanged(toName(Boundnumber));,但它没有让我到任何地方。非常感谢!
    【解决方案2】:

    你还没有在任何地方初始化你的PropertyChanged 事件,所以它永远不会被调用。像这样声明并初始化它:

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    【讨论】:

    • 感谢您的回复。我也无法让它工作。 PropertyChanged 事件似乎有效,但我认为 QuickMath 属性在 UI 中编辑之前不会被初始化,但我不确定。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-03
    相关资源
    最近更新 更多