Reputation: 71
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.
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
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