【问题标题】:TwoWay binding on a DataGrid in WPFWPF 中 DataGrid 上的双向绑定
【发布时间】:2023-03-13 11:21:01
【问题描述】:

我有一个 WPF DataGrid 正在使用

var allLines = from Lines in ctx.InvoiceLines join PerPs in ctx.ProductsViews on Lines.ProductCode equals PerPs.ProductCode 
               where (Lines.BranchNo == BrNo) && (Lines.Docket == Docket)
               select new { Lines.ProductCode, Lines.Description, Lines.Inv_Quantity, Lines.Grn_Quantity,
                Lines.Inv_Price,Lines.Grn_Price,Lines.Inv_Total, Lines.Grn_Total, Lines.AnalCode,
                Lines.Vat_Rate, Lines.GrnNo,Lines.Comment , PerPs.OuterUnits};

dgGrid.ItemsSource = allLines;

我想在更改任何值或添加新行时使用两种方式绑定来更新数据库。这可能吗?

我的 xaml 代码是

<DataGrid Grid.Row="3" x:Name="dgGrid" DataContext="{Binding}" FontSize="16" HorizontalScrollBarVisibility="Visible" 
              VerticalScrollBarVisibility="Visible" SelectionUnit="FullRow" SelectionMode="Extended" AutoGenerateColumns="False"
              SelectionChanged="dgGrid_SelectionChanged" >
        <DataGrid.Columns>
            <DataGridTextColumn Width="Auto" Header="ProductCode"  Binding="{Binding ProductCode, Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="250" Header="Description"  Binding="{Binding Description,  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}" FontSize="14"/>
            <DataGridTextColumn Width="61" Header="Inv_Quantity" Binding="{Binding Inv_Quantity,  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="63" Header="Grn_Quantity" Binding="{Binding Grn_Quantity,  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="59" Header="Inv_Price" Binding="{Binding Inv_Price,  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="61" Header="Ord_Price" Binding="{Binding Grn_Price,  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="72" Header="Inv_Total" Binding="{Binding Inv_Total, Converter={StaticResource Currency},  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="74" Header="Grn_Total" Binding="{Binding Grn_Total, Converter={StaticResource Currency},  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="58" Header="AnalCode" Binding="{Binding AnalCode,  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="40" Header="Vat_Rate" Binding="{Binding Vat_Rate,  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="Auto" Header="GrnNo"  Binding="{Binding GrnNo,  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="Auto" Header="Comment" Binding="{Binding Comment, Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="Auto" Header="PerP" Binding="{Binding OuterUnits}" IsReadOnly="True"/>
        </DataGrid.Columns>
        <DataGrid.Resources>
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="LightSteelBlue"/>
        </DataGrid.Resources>
    </DataGrid>

当我运行这段代码时,除了 PerP 列是空的。

我不知道如何做最好的方法,所以非常感谢任何帮助。

【问题讨论】:

    标签: c# wpf xaml wpfdatagrid


    【解决方案1】:

    除了“PerP”列之外,您的DataGridTextColumn 的所有Bindings 都指定了两次路径。例如:

    <DataGridTextColumn Width="Auto" Header="ProductCode"  Binding="{Binding ProductCode, Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
    

    在这里,您的Binding 首先将路径指定为“ProductCode”,然后还将其指定为“IsSelected”。由于您要绑定到网格的集合中的对象上没有“IsSelected”属性,因此如果您在调试器下运行它,您应该会在“输出”窗口中看到绑定错误。如果您删除了这些绑定的 Path=IsSelected,那么列值应该被正确绑定。

    您的数据源是一个匿名类型的集合,因此var 是必要的,但正如其他人所说的那样,与该集合的双向绑定不适用于更新回源。

    【讨论】:

    • 还有其他方法可以支持更新的双向绑定吗?
    • 是的,通过绑定到您要更新的实际对象的实例,在您的情况下,这将是实体框架跟踪的实体。我假设最终您希望将更改保存回数据库,因此更新影响正在执行更改跟踪的 EF 实体是有意义的,以便以后可以将所有更改刷新到数据库。
    • 您能否提供任何网站的链接来说明如何做到这一点?
    • 谢谢史蒂夫,这真是个好视频,我想它正是我需要的。 :)
    • @Steve Rowbotham,我从那个视频中得到一种奇怪的感觉,好像我在平行宇宙中。创建 EF 模型时,我从未获得数据源。我认为数据源只是用于老式表适配器。
    【解决方案2】:

    您的allLines 变量是匿名类型的可枚举。在 C# 中,匿名类型是只读的 - 无法编辑属性,也无法保存更改。

    尝试进行查询:

    var allLines = 
        from Lines in ctx.InvoiceLines 
        join PerPs in ctx.ProductsViews on Lines.ProductCode equals PerPs.ProductCode 
        where (Lines.BranchNo == BrNo) && (Lines.Docket == Docket)
        select Lines;
    
    dgGrid.ItemsSource = allLines.ToList();
    

    【讨论】:

    • 不要将查询结果投影到匿名类型的集合中(即使用new {...}),而是选择Paul 上面显示的实际行,因为它们应该跟踪对它们所做的更改。
    【解决方案3】:

    如果“allLines”变量是DataTable,您只需将DataGrid 的AutoGenerateColumns 设置为true。
    您也不需要使用“DataContext”属性,而是使用“ItemsSource”。
    像这样的:

    <DataGrid ItemsSource="{Binding Path=allLines.DefaultView}" ... />
    

    要根据更改更新数据库,请调用数据表的 Update() 方法,例如单击“保存”按钮。

    如果“allLines”不是DataTable,那么去掉这个地狱般的“var”关键字,告诉我们变量的真实性质=)

    【讨论】:

    • 当我使用 ItemsSource 时,DG 是空的。我不知道 allLines 实际上是什么数据类型
    • TBH 从代码中可以清楚地看出,赋值左侧的变量不是 DataTable,所以这不相关。它显然是一个匿名类型的集合,因此 var 是必要的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-23
    • 1970-01-01
    • 2015-04-26
    • 1970-01-01
    • 2015-05-21
    • 2011-02-25
    • 1970-01-01
    相关资源
    最近更新 更多