Вычисляемое поле не обновляется, пока не отредактировано в пользовательском интерфейсе - PullRequest
1 голос
/ 17 июня 2019

Я пытаюсь проверить привязку данных с XAML и C # как начинающий программист.У меня есть два ползунка, которые привязаны к свойствам, и я хочу обновить TextBox суммой двух значений свойств, установленных ползунками.

Я использую INotifyPropertyChanged и попытался изменить каждое свойство Iмог найти, но я не могу получить текстовое поле для обновления, пока я не отредактирую текстовое поле, после чего текстовое поле обновляется до правильного значения.Использование 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();, но я надеялся, что есть лучший способ сделать это с привязкой данных.Спасибо в ожидании!

Ответы [ 2 ]

0 голосов
/ 17 июня 2019
Механизм связывания

подписывается на событие PropertyChanged объекта DataSource, поэтому нет необходимости «инициализировать» событие вместе с реализацией INPC, но, как вы могли заметить, событие PropertyChanged дляСвойство QuickMath действительно никогда не срабатывает при изменении BoundNumber или BoundNumber2.

Вы можете исправить это различными способами, например, явно вызвать OnPropertyChanged для всех затронутых свойств:

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

Обратите внимание, что таким образом вы можете оставить свойство QuickMath доступным только для чтения.Этот подход хорошо работает в других ситуациях, например, со свойствами, связанными со временем, например, если ваше свойство источника данных форматирует строку, такую ​​как «Отредактировано 2 минуты назад» на основе записанной отметки времени и текущего времени, и вы вызываете PropertyChanged как временное задание.

public int QuickMath => _boundNumber + _boundNumber2;

В качестве альтернативы вы можете обновить QuickMath вместе с изменением BoundNumber и BoundNumber2, чтобы инициировать OnPropertyChanged() вызов внутри QuickMath сеттер:

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

Это имеет смысл, если логика в QuickMath не позволяет сделать его доступным только для чтения.В этом случае вы должны соответствующим образом настроить геттер и использовать частный или защищенный сеттер, чтобы избежать несогласованности данных и неожиданного поведения.

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}"/>

Что касается сопутствующей заметки и обзора остальной части кода, стоит упомянуть, что механизм связывания должен отделять пользовательский интерфейс от данных, где XAML знает о свойствах объекта источника данных (именах).и типы), но не о его внутренней реализации, в то время как объект источника данных может вообще ничего не знать о XAML.Так что

  1. не должно быть никаких вызовов от объекта данных к FrameworkElement s, как MathBox.Text
  2. считается хорошим дизайном, когда класс объекта данных полностью отделен от страницы или элемента управлениякласс.

Надеюсь, это поможет.

0 голосов
/ 17 июня 2019

Вы нигде не инициализировали ваше событие PropertyChanged, поэтому оно никогда не будет вызвано.Объявите и инициализируйте его так:

public event PropertyChangedEventHandler PropertyChanged = delegate { };

...