如何使用自定义 RowStyle 编辑 WPF DataGrid 中的行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13943325/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 06:40:28  来源:igfitidea点击:

How to edit rows in a WPF DataGrid with a custom RowStyle

c#wpfxamlmvvmdatagrid

提问by Sphinxxx

I need to put some data in a DataGrid, using a custom UserControlfor each row. Displaying the data works just fine, but when I edit the fields in the custom UserControl, the bound data records don't change.

我需要将一些数据放入 a 中DataGridUserControl对每一行使用自定义。显示数据工作正常,但是当我编辑 custom 中的字段时UserControl,绑定的数据记录不会改变。

If I use a ListBoxto display the data instead, it all works as expected. But I would rather use the DataGrid, which allows for sorting and (hopefully) adding new records.

如果我使用 aListBox来显示数据,它会按预期工作。但我更愿意使用 DataGrid,它允许排序和(希望)添加新记录。

To illustrate, here is a simple data class that I need to display (and edit) - persons and their spouses:

为了说明,这里有一个我需要显示(和编辑)的简单数据类 - 人和他们的配偶:

public class PersonViewModel : INotifyPropertyChanged
{
    public PersonViewModel(string name)
    {
        _name = name;
    }

    private string _name = null;
    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            this.PropertyChanged(this, new PropertyChangedEventArgs("Name"));
        }
    }

    private PersonViewModel _spouse = null;
    public PersonViewModel Spouse
    {
        get { return _spouse; }
        set
        {
            _spouse = value;
            this.PropertyChanged(this, new PropertyChangedEventArgs("Spouse"));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged = (s, e) => { };
}

..and here is the custom UserControl (PersonView):

..这里是自定义用户控件(PersonView):

<UserControl x:Class="TestDataGrid.PersonView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" >
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <!--Editing in DataGrid works only if these bindings use UpdateSourceTrigger=PropertyChanged-->
        <TextBox Text="{Binding Path=Name}" Width="70" />
        <TextBlock Text="is married to" Margin="6,0" Grid.Column="1" />
        <TextBox Text="{Binding Path=Spouse.Name}" Width="70" Grid.Column="2" />
    </Grid>
</UserControl>

Finally, the main window (with code-behind) to put it all together:

最后,将主窗口(带有代码隐藏)放在一起:

<Window x:Class="TestDataGrid.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TestDataGrid"
        Title="MainWindow" Height="350" Width="500">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <!--Changes made here correctly update the persons' names,
            and the changes are reflected in the DataGrid below-->
        <ListBox x:Name="_listbox" >
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <local:PersonView />
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

        <!--Changes made here never reach the PersonViewModels..-->
        <DataGrid x:Name="_datagrid" Grid.Column="1" 
                  AutoGenerateColumns="False" CanUserAddRows="True" IsReadOnly="False" >
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Path=Name}" Header="Name" />
                <DataGridTextColumn Binding="{Binding Path=Spouse.Name}" Header="Spouse" />
            </DataGrid.Columns>
            <DataGrid.RowStyle>
                <Style TargetType="DataGridRow" >
                    <Setter Property="Template" >
                        <Setter.Value>
                            <ControlTemplate>
                                <local:PersonView />
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </DataGrid.RowStyle>
        </DataGrid>
    </Grid>
</Window>

...

...

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        var personA = new PersonViewModel("Alice");
        var personB = new PersonViewModel("Barry");
        var personC = new PersonViewModel("Carl");
        var personD = new PersonViewModel("Doris");

        personA.Spouse = personB;
        personC.Spouse = personD;
        var persons = new List<PersonViewModel>() { personA, personC };

        _listbox.ItemsSource = persons;
        _datagrid.ItemsSource = persons;
    }

}

What can I do to make editing work in the DataGrid, as it does in the ListBox?

我可以怎样做才能在 DataGrid 中进行编辑,就像在 ListBox 中一样?

回答by David

I twiddled with your code a bit and I think I got it working.

我玩弄了你的代码,我想我已经开始工作了。

First of all, you have a note on your PersonView that says "Editing in DataGrid works only if these bindings use UpdateSourceTrigger=PropertyChanged." I found that it WAS necessary to set UpdateSourceTrigger, but I used LostFocus to try and keep the same behavior as is in the ListBox.

首先,您在 PersonView 上有一条注释,上面写着“仅当这些绑定使用 UpdateSourceTrigger=PropertyChanged 时,才能在 DataGrid 中进行编辑。” 我发现有必要设置 UpdateSourceTrigger,但我使用 LostFocus 来尝试保持与 ListBox 中相同的行为。

<!--Editing in DataGrid works only if these bindings use UpdateSourceTrigger-->
    <TextBox Text="{Binding Path=Name, UpdateSourceTrigger=LostFocus}" Width="70" />
    <TextBlock Text="is married to" Margin="6,0" Grid.Column="1" />
    <TextBox Text="{Binding Path=Spouse.Name, UpdateSourceTrigger=LostFocus}" Width="70" Grid.Column="2" />

Second, instead of using 2 DataGridTextColumns and DataGrid.RowStyle, I used a single DataGridTemplateColumn. I hope this is acceptable--it appears the way you had it before, the template wasn't really honoring the columns, but it does now.

其次,我没有使用 2 个 DataGridTextColumns 和 DataGrid.RowStyle,而是使用了一个 DataGridTemplateColumn。我希望这是可以接受的——它看起来像你以前那样,模板并没有真正尊重列,但现在确实如此。

        <DataGrid x:Name="_datagrid" Grid.Column="1" AutoGenerateColumns="False" CanUserAddRows="True" IsReadOnly="False" >
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="People">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <local:PersonView />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>

After making these changes, I saw it updating on both sides.

进行这些更改后,我看到它在两侧都有更新。

I hope that helps you.

我希望这对你有帮助。