在数据表格中:如何在更改单元格A的值后显示单元格B中的变化。

huangapple go评论65阅读模式
英文:

In a Datagrid: How to display change in cell B after changing value in cell A

问题

我有一个使用 CommunityToolkit.WinUI.UI.Controls.DataGrid 的 WinUI3 项目。
我有一个绑定到 DataGridObservableCollection<ExampleClass>
ExampleClass 的相关变量是:Amount int, Price int, TotalPrice int
我向我的 datagrid 添加了一个事件 CellEditEnded,它将 TotalPrice 更新为 Amount * Price
用户在运行时更改 datagrid 中的 AmountPrice 后,但是对于 TotalPrice 的任何更改,仍然存在以下问题。
价格在应用程序开始时是 10。当用户将 Amount 更改为比如 2 时,该 ExampleClass 实例的 TotalPrice 单元格仍然显示 0(0 个 Amount * 10 个 Price)。我已经检查过 TotalPrice 的值已经在 Observablecollection 中正确更改。问题是 DataGrid 不会显示更改。当我重新加载页面时,更改最终会正确进行。或者当用户开始编辑 TotalPrice 单元格时,正确的值突然显示出来并保留在单元格中。有趣的是,当我尝试手动更改 totalprice 值时,它总是返回到正确的值。

有了这个问题,用户在编辑了 amount 或 price 后,总是不得不开始编辑所有过时的 totalprice 单元格,才能看到正确的值。或者他重新加载页面以查看所有正确的值。

当单元格 A(Amount 或 Price)更改时,DataGrid 似乎不会更新单元格 B(TotalPrice)。

Amount = Anzahl,Price = Preis

<controls:DataGrid 
    AutoGenerateColumns="False"
    GridLinesVisibility="Horizontal"
    ItemsSource="{x:Bind ViewModel.kgr.Tabelle1, Mode=OneWay}"
    Grid.Column="0"
    Grid.Row="0"
    CellEditEnded="DataGrid_CellEditEnded>
    <controls:DataGrid.Resources>
        <SolidColorBrush x:Key="DataGridColumnHeaderBackgroundColor" Color="Transparent" />
    </controls:DataGrid.Resources>
    <controls:DataGrid.Columns>
        <controls:DataGridTextColumn Binding="{Binding Name}" Header="Bereich" />
        <controls:DataGridTextColumn Binding="{Binding Anzahl}" Header="Fläche in m^2" />
        <controls:DataGridTextColumn Binding="{Binding Preis}" Header="€ pro m^2" />
        <controls:DataGridTextColumn Binding="{Binding TotalPreis}" Header="Gesamt"/>
    </controls:DataGrid.Columns>
</controls:DataGrid>

我专注于 xaml 文件,因为数据源工作得很好。
我尝试了与 celleditevent 相关的替代方法,itemsource 中的绑定模式,itemsource、datagrid 本身、totalprice 列和 totalprice 绑定属性等的其他 xaml 属性。
这些属性中的许多都有有希望的名称(如 UpdateSourceTrigger、Bindmode = twoway),但我尝试了很多,似乎没有一个能工作。
我可能漏掉了什么,但是一般的文档和 winui3 的年轻时代并没有帮助,
我无法想象这个功能在 Microsoft 的 UI 框架中不存在。

WPF 开发人员使用 propertychanged,我搜索了一下这个名称,并发现它是 Datagridtextcolumn 内部的绑定的属性或者 itemsource 内部的属性,但是文档是这样的:链接

甚至临时的、不太优雅的解决方法都可以,比如重新加载 datagrid,我只需要一些东西。

希望能得到一些帮助。

英文:

I have a winui3 project using the CommunityToolkit.WinUI.UI.Controls.DataGrid.
I have an ObservableCollection<ExampleClass> that I bind to a DataGrid.
The relevant variables of the ExampleClass are: Amount int, Price int, TotalPrice int.
I added an event to my datagrid, CellEditEnded, which updates the TotalPrice to Amount * Price.
After the user changes Amount or Price in the datagrid at runtime, but the following problem is still there with any kind of change to the value of TotalPrice.
Price is == 10 at the start of the app. When the user changes Amount to let's say 2, the Totalprice Cell of that ExampleClass instance still shows 0 (0 amount * 10 price). I have checked and the TotalPrice value has correctly changed in the Observablecollection. The problem is that the DataGrid won't show the change. When I reload the page, the change is finally made correctly. Alternatively when the user starts editing the TotalPrice cell, the correct value suddenly shows up and stays in the cell. Funny also when I try to change the totalprice value manually, it always goes back to the correct value.

With this problem the user, after editing amount or price, always has to start editing all the outdated totalprice cells to see the correct value. OR he reloads the page to see all correct values.

The DataGrid seems not to update cell B (TotalPrice) when cell A (Amount or Price) is changed.

Amount = Anzahl, Price = Preis

<controls:DataGrid 
    AutoGenerateColumns="False"
    GridLinesVisibility="Horizontal"
    ItemsSource="{x:Bind ViewModel.kgr.Tabelle1, Mode=OneWay}"
    Grid.Column="0"
    Grid.Row="0"
    CellEditEnded="DataGrid_CellEditEnded>
    <controls:DataGrid.Resources>
        <SolidColorBrush x:Key="DataGridColumnHeaderBackgroundColor" Color="Transparent" />
    </controls:DataGrid.Resources>
    <controls:DataGrid.Columns>
        <controls:DataGridTextColumn Binding="{Binding Name}" Header="Bereich" />
        <controls:DataGridTextColumn Binding="{Binding Anzahl}" Header="Fläche in m^2" />
        <controls:DataGridTextColumn Binding="{Binding Preis}" Header="€ pro m^2" />
        <controls:DataGridTextColumn Binding="{Binding TotalPreis}" Header="Gesamt"/>
        <!-- IsReadOnly="True" -->
    </controls:DataGrid.Columns>
</controls:DataGrid>

I focused on the xaml file because the datasource is working all well.
There I tried alternatives to the celleditevent, Binding Modes in the itemsource, other xaml properties in the: itemsource, datagrid itself, totalprice column, totalprice binding property etc etc.
many of these properties had promising names (like UpdateSourceTrigger, Bindmode = twoway), but I tried alot of them and none seem to work.
I am probably missing something but the mediocre documentation and young age of winui3 doesn't help,
and I can't imagine that this feature wouldn't exist in a UI framework of Microsoft.

WPF devs use propertychanged, I looked for something with that name and found its a property of binding inside Datagridtextcolumn or a property inside itemsource, but the documentation is this https://learn.microsoft.com/en-us/dotnet/api/communitytoolkit.winui.ui.controls.datagridboundcolumn.binding?view=win-comm-toolkit-dotnet-7.0#communitytoolkit-winui-ui-controls-datagridboundcolumn-binding

Even a temporary inelegant fix will do, like reloading the datagrid, I just need something.

Hoping for some help.

答案1

得分: 1

以下是您要翻译的内容:

我的第一个猜测是您没有在属性上实现INotifyPropertyChanged

这是一个使用CommunityToolkit.Mvvm NuGet包的示例代码,它将为您生成实现INotifyPropertyChanged的代码。

Item.cs

public partial class Item : ObservableObject
{
    [ObservableProperty]
    private string name = string.Empty;

    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(Total))]
    private int price;

    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(Total))]
    private int quantity;

    public int Total => Price * Quantity;
}

MainPageViewModel.cs

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

    public MainPageViewModel()
    {
        Items.Add(new Item { Name = "A", Price = 100, Quantity = 1 });
        Items.Add(new Item { Name = "B", Price = 200, Quantity = 2 });
        Items.Add(new Item { Name = "C", Price = 300, Quantity = 3 });
        Items.Add(new Item { Name = "D", Price = 400, Quantity = 4 });
        Items.Add(new Item { Name = "E", Price = 500, Quantity = 5 });
    }
}

MainPage.xaml

<Page
    x:Class="DataGridExample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:controls="using:CommunityToolkit.WinUI.UI.Controls"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="using:DataGridExample"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    mc:Ignorable="d">
    <Page.DataContext>
        <local:MainPageViewModel x:Name="ViewModel" />
    </Page.DataContext>

    <Grid>
        <controls:DataGrid
            AutoGenerateColumns="False"
            ItemsSource="{x:Bind ViewModel.Items, Mode=OneWay}">
            <controls:DataGrid.Columns>
                <controls:DataGridTextColumn
                    Binding="{Binding Name}"
                    Header="Name"
                    IsReadOnly="True" />
                <controls:DataGridTextColumn
                    Binding="{Binding Price}"
                    Header="Price" />
                <controls:DataGridTextColumn
                    Binding="{Binding Quantity}"
                    Header="Quantity" />
                <controls:DataGridTextColumn
                    Binding="{Binding Total}"
                    Header="Total"
                    IsReadOnly="True" />
            </controls:DataGrid.Columns>
        </controls:DataGrid>
    </Grid>
</Page>
英文:

My first guess is that you are not implementing INotifyPropertyChange on your properties.

This is a sample code the uses the CommunityToolkit.Mvvm NuGet package the will generate code that implements INotifyPropertyChanged for you.

Item.cs

public partial class Item : ObservableObject
{
    [ObservableProperty]
    private string name = string.Empty;

    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(Total))]
    private int price;

    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(Total))]
    private int quantity;

    public int Total =&gt; Price * Quantity;
}

MainPageViewModel.cs

public partial class MainPageViewModel : ObservableObject
{
    [ObservableProperty]
    private ObservableCollection&lt;Item&gt; items = new();

    public MainPageViewModel()
    {
        Items.Add(new Item { Name = &quot;A&quot;, Price = 100, Quantity = 1 });
        Items.Add(new Item { Name = &quot;B&quot;, Price = 200, Quantity = 2 });
        Items.Add(new Item { Name = &quot;C&quot;, Price = 300, Quantity = 3 });
        Items.Add(new Item { Name = &quot;D&quot;, Price = 400, Quantity = 4 });
        Items.Add(new Item { Name = &quot;E&quot;, Price = 500, Quantity = 5 });
    }
}

MainPage.xaml

&lt;Page
    x:Class=&quot;DataGridExample.MainPage&quot;
    xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
    xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;
    xmlns:controls=&quot;using:CommunityToolkit.WinUI.UI.Controls&quot;
    xmlns:d=&quot;http://schemas.microsoft.com/expression/blend/2008&quot;
    xmlns:local=&quot;using:DataGridExample&quot;
    xmlns:mc=&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
    Background=&quot;{ThemeResource ApplicationPageBackgroundThemeBrush}&quot;
    mc:Ignorable=&quot;d&quot;&gt;
    &lt;Page.DataContext&gt;
        &lt;local:MainPageViewModel x:Name=&quot;ViewModel&quot; /&gt;
    &lt;/Page.DataContext&gt;

    &lt;Grid&gt;
        &lt;controls:DataGrid
            AutoGenerateColumns=&quot;False&quot;
            ItemsSource=&quot;{x:Bind ViewModel.Items, Mode=OneWay}&quot;&gt;
            &lt;controls:DataGrid.Columns&gt;
                &lt;controls:DataGridTextColumn
                    Binding=&quot;{Binding Name}&quot;
                    Header=&quot;Name&quot;
                    IsReadOnly=&quot;True&quot; /&gt;
                &lt;controls:DataGridTextColumn
                    Binding=&quot;{Binding Price}&quot;
                    Header=&quot;Price&quot; /&gt;
                &lt;controls:DataGridTextColumn
                    Binding=&quot;{Binding Quantity}&quot;
                    Header=&quot;Quantity&quot; /&gt;
                &lt;controls:DataGridTextColumn
                    Binding=&quot;{Binding Total}&quot;
                    Header=&quot;Total&quot;
                    IsReadOnly=&quot;True&quot; /&gt;
            &lt;/controls:DataGrid.Columns&gt;
        &lt;/controls:DataGrid&gt;
    &lt;/Grid&gt;
&lt;/Page&gt;

huangapple
  • 本文由 发表于 2023年5月22日 18:34:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76305298.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定