samgido
samgido

Reputation: 71

Trigger ValueChanged Event after Properties are updated?

I have a bunch of NumberBoxes created from an ItemsRepeater, and I need the app to sum all the values and display them. However, when I type a value in, I have to go to a different NumberBox, type a number in there and press enter for the original number to be included in the displayed sum. This behavior is shown in the gif where I am pressing enter a few times after typing in a number, and the number to the left of "Accumulated Area" should be the sum of all fields. enter image description here

Currently, I am using the ValueChanged event to call an update on the data model for the page that iterates through the properties bound to the number boxes and adds them to create the accumulated sum.

private void Values_Changed(NumberBox sender, NumberBoxValueChangedEventArgs args) 
{
  DataModel.Update();
}

I might be wrong, but the properties the NumberBoxes are bound to aren't updating before .Update() is called. I the properties to update before the update method is called.

Upvotes: 0

Views: 172

Answers (1)

Andrew KeepCoding
Andrew KeepCoding

Reputation: 13761

The ValueChanged event is fired when the NumberBox's value is changed. And the bound value is changed after the NumberBox's value is changed.

I recommend that you do this on the ViewModel side.

For example:

Item.cs

public partial class Item : ObservableObject
{
    [ObservableProperty]
    private double _value;

    public event EventHandler<(double oldValue, double newValue)>? ValueChanged;

    partial void OnValueChanged(double oldValue, double newValue)
    {
        this.ValueChanged?.Invoke(this, (oldValue, newValue));
    }
}

MainViewModelViewModel.cs

public partial class  MainWindowViewModel : ObservableObject
{
    [ObservableProperty]
    private ObservableCollection<Item> _items = new();

    [ObservableProperty]
    private double _resultValue = 0;

    public MainWindowViewModel()
    {
        for (int i = 0; i < 10; i++)
        {
            Item item = new();
            item.ValueChanged += Item_ValueChanged;
            this.Items.Add(item);
        }
    }

    private void Item_ValueChanged(object? sender, (double oldValue, double newValue) e)
    {
        this.ResultValue = this.Items.Sum(x => x.Value);
    }
}

MainWindow.xaml.cs

public sealed partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();
    }

    private MainWindowViewModel ViewModel { get; } = new();
}

MainWindow.xaml

<ItemsRepeater ItemsSource="{x:Bind ViewModel.Items, Mode=OneWay}">
    <ItemsRepeater.ItemTemplate>
        <DataTemplate x:DataType="local:Item">
            <NumberBox Value="{x:Bind Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        </DataTemplate>
    </ItemsRepeater.ItemTemplate>
</ItemsRepeater>
<TextBlock Text="{x:Bind ViewModel.ResultValue, Mode=OneWay}" />

NOTE:

ObservableObject and ObservableProperty comes from the CommunityToolkit.Mvvm for the MVVM design.

Upvotes: 0

Related Questions