问题
I need to put some data in a DataGrid
, using a custom UserControl
for 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.
If I use a ListBox
to 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.
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):
<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?
回答1:
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.
<!--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.
<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.
来源:https://stackoverflow.com/questions/13943325/how-to-edit-rows-in-a-wpf-datagrid-with-a-custom-rowstyle