我有一个 DataGrid,用户可以通过在最后一行输入数据来添加项目。我还有一个按钮可以删除当前选定的项目。但是,当选择最后一行(空,用于添加新项目)时,最后选定的项目将保留在 SelectedItem 中。因此,如果我打开窗口,选择最后一行,然后按删除按钮,它将删除第一行,因为默认情况下会选择第一行,并且选择最后一行不会更改 SelectedItem。有什么好的办法解决吗?
澄清一下: SelectedItem="{绑定X}"
当选择最后一行时,ViewModel 中的 X 不会改变(根本不调用 setter)。我不确定 SelectedItem 属性本身是否改变,但我假设它没有改变。当我选择最后一行(红色边框)时也有一个例外,但是当我再次单击它开始输入数据时,红色边框消失了。不确定这两者是否相关。
XAML:
<Window x:Class="DataGridTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<TextBlock DockPanel.Dock="Bottom" Text="{Binding SelectedItem, ElementName=dataGrid}"/>
<TextBlock DockPanel.Dock="Bottom" Text="{Binding SelectedItem}"/>
<DataGrid x:Name="dataGrid" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" CanUserAddRows="True" CanUserDeleteRows="True" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}"/>
<DataGridTextColumn Header="Last Name" Binding="{Binding FirstName}"/>
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Window>
后台代码:
namespace DataGridTest
{
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
public partial class MainWindow : Window, INotifyPropertyChanged
{
private readonly ICollection<Person> items;
private Person selectedItem;
public MainWindow()
{
InitializeComponent();
this.items = new ObservableCollection<Person>();
this.items.Add(new Person
{
FirstName = "Kent",
LastName = "Boogaart"
});
this.items.Add(new Person
{
FirstName = "Tempany",
LastName = "Boogaart"
});
this.DataContext = this;
}
public ICollection<Person> Items
{
get { return this.items; }
}
public Person SelectedItem
{
get { return this.selectedItem; }
set
{
this.selectedItem = value;
this.OnPropertyChanged("SelectedItem");
}
}
private void OnPropertyChanged(string propertyName)
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class Person
{
public string FirstName
{
get;
set;
}
public string LastName
{
get;
set;
}
public override string ToString()
{
return FirstName + " " + LastName;
}
}
}
正如您在运行时所看到的,选择“新”行会导致哨兵值被设置为DataGrid
中的所选项目。但是,WPF 无法将该哨兵项转换为
Person
,因此
SelectedItem
绑定无法转换。要解决此问题,您可以在绑定上放置一个转换器来检测哨兵并在检测到时返回
null
。这是一个这样做的转换器:
namespace DataGridTest
{
using System;
using System.Windows.Data;
public sealed class SentinelConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value.Equals(CollectionView.NewItemPlaceholder))
{
return null;
}
return value;
}
}
}
如您所见,不幸的是,需要针对哨兵的 ToString()
值进行测试,因为它是内部类型。您也可以(或另外)检查
GetType().Name
是否为
NamedObject
。
确保每当删除一个项目并且它也是选定的项目时,将绑定到 ViewModel 中的属性的选定项目设置为 null。您需要确保绑定到属性的 SelectedItem 不是单向绑定的。
并始终确保您拥有正确的数据上下文。
希望有帮助。