首页 文章

WPF DataGrid SelectedItem

提问于
浏览
5

我有一个DataGrid,用户可以通过在最后一行输入数据来添加项目 . 我还有一个删除当前所选项目的按钮 . 但是当选择最后一个(空的,用于添加新项目)行时,最后选择的项目保留在SelectedItem中 . 因此,如果我打开窗口,选择最后一行,然后按删除按钮,它将删除第一行,因为它是默认选中的,并且选择最后一行不会更改SelectedItem . 有什么好方法可以解决这个问题吗?

澄清:SelectedItem =“

选择最后一行时,ViewModel中的X不会更改(根本不调用setter) . 我不确定SelectedItem属性本身是否会发生变化,但我认为它不会 .

当我选择最后一行(红色边框)时也有一个例外,但当我再次单击它以开始输入数据时,红色边框会消失 . 不确定这两者是否相关 .

3 回答

  • 0

    运行以下示例,您将看到它为什么不起作用 .

    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无法将该sentinel项转换为 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 != null && string.Equals("{NewItemPlaceholder}", value.ToString(), StringComparison.Ordinal))
                {
                    return null;
                }
    
                return value;
            }
        }
    }
    

    正如您所看到的,测试哨兵的 ToString() 值是一个不幸的必要,因为它是一种内部类型 . 您也可以(或另外)检查 GetType().NameNamedObject .

  • 0

    没有代码很难说,但我会看下面的内容 .

    确保每当删除一个项目并且它也是所选项目时,将ViewModel中绑定到property的选定项目设置为null . 您需要确保绑定到属性的SelectedItem不会被绑定 .

  • 11

    听起来你忘了设置绑定模式,默认设置为OneWay . 这意味着您的视图中所做的任何更改都不会传播回您的视图模型 .

    并始终确保您拥有正确的datacontext .

    希望有所帮助 .

相关问题