WPF中DataGrid的双向绑定

3

我有一个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列外,其他列都是空的。 我很迷茫,不知道最佳方法应该怎么做,所以任何帮助都将不胜感激。
3个回答

4
除了“PerP”列之外,所有与您的DataGridTextColumn相关的Bindings都会重复指定路径。例如:
<DataGridTextColumn Width="Auto" Header="ProductCode"  Binding="{Binding ProductCode, Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>

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

您的数据源是一个匿名类型的集合,所以var是必要的,但正如其他人所说,对该集合进行双向绑定不会使更新返回到源。


有没有其他的方法可以支持双向绑定更新? - Noelle
1
是的,通过绑定到您想要更新的实际对象的实例,这在您的情况下将是Entity Framework跟踪的实体。我假设最终您希望更改保存回数据库,因此更新应影响进行更改跟踪的EF实体,以便稍后可以将所有更改刷新到数据库。 - Steve Rowbotham
你有没有任何网站的链接可以展示如何实现这个? - Noelle
谢谢Steve,这个视频真的很棒,我觉得正是我需要的。 :) - Noelle
@Steve Rowbotham,我从那个视频中感到一种奇怪的感觉,好像我在一个平行宇宙里。当我创建EF模型时,我从来没有得到过数据源。我认为数据源只是用于旧式表适配器。 - Sam Hobbs

2
如果“allLines”变量是一个DataTable,您可以将DataGrid的AutoGenerateColumns属性设置为true。
您也不需要使用"DataContext"属性,而应该使用"ItemsSource"属性。
像这样的代码:
<DataGrid ItemsSource="{Binding Path=allLines.DefaultView}" ... />

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

如果“allLines”不是DataTable,则删除这个可怕的“var”关键字并告诉我们变量的真实本质=)


当我使用ItemsSource时,DG为空。我不知道allLines实际上是什么数据类型。 - Noelle
1
老实说,从代码中可以很清楚地看出赋值左侧的变量不是 DataTable,因此与此无关。这显然是一个匿名类型的集合,所以 var 是必要的。 - Steve Rowbotham

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();

1
不要像使用“new {...}”那样将查询结果投影到匿名类型的集合中,而是像Paul上面展示的那样选择实际的Lines,因为它们应该跟踪所做的更改。 - Steve Rowbotham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接