WPF数据网格选定项

6
我有一个DataGrid,用户可以通过在最后一行输入数据来添加项目。我还有一个按钮,用于删除当前选定的项目。但当选择最后一行(空行,用于添加新项目)时,无论之前选择过什么项目,选定的项目都会保留在SelectedItem中。因此,如果我打开窗口,选择最后一行并按下删除按钮,则会删除第一行,因为它是默认选择的,并且选择最后一行不会更改SelectedItem。有没有好的处理方法?
为了澄清: SelectedItem = "{Binding X}"
当选择最后一行时,ViewModel中的X不会更改(setter根本不会被调用)。我不确定是否会更改SelectedItem属性本身,但我想它不会。
当我选择最后一行时(红色边框),也会出现异常,但当我再次单击它开始输入数据时,红色边框就会消失。不确定这两个问题是否相关。
3个回答

12

运行下面的示例,你会看到为什么它不起作用。

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;
        }
    }
}

如您所见,运行时选择“new”行会导致在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 (item.Equals(CollectionView.NewItemPlaceholder)))
            {
                return null;
            }

            return value;
        }
    }
}

正如您所看到的,不幸的是必须对哨兵的ToString()值进行测试,因为它是一个内部类型。您还可以(或者另外)检查GetType().Name是否为NamedObject


4
5年后,但是现在可以把它放在这里:您可以将其与CollectionView.NewItemPlaceholder进行比较,这是您正在做的相同事情,而无需在代码中烧录“{NewItemPlaceholder}”字符串。 - Guj Mil

0
很难在没有代码的情况下说,但我会关注以下几点。
确保每当删除一个项目并且它也是选定的项目时,将选定的项目绑定到ViewModel中的属性设置为null。您需要确保SelectedItem绑定的属性不是单向绑定。

0

听起来你可能忘记设置绑定模式,而默认设置为单向。这意味着在视图中所做的任何更改都不会传播回视图模型。

并且始终确保您拥有正确的数据上下文。

希望能帮到你。


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