WPF DataGrid.SelectedItem在移动到CollectionChanged事件处理程序中的最后一项时不会突出显示 [英] WPF DataGrid.SelectedItem does not highlight when moved to last item in CollectionChanged event handler

查看:79
本文介绍了WPF DataGrid.SelectedItem在移动到CollectionChanged事件处理程序中的最后一项时不会突出显示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法弄清楚在这种情况下到底出了什么问题.基本上,我的视图模型中有一个绑定到ObservableCollection的DataGrid. DataGrid的SelectedItem也绑定到我的视图模型中的一个属性.然后我有一个命令 对所选项目执行删除操作.我还为CollectionChanged添加了一个事件处理程序,以便在从集合中删除一个项目时可以通知我.在该事件处理程序中,我将选定的item属性更新为 相同的索引(如果是最后一项,则为先前的索引).我在集合更改事件处理程序中执行此操作,因为该集合从多个位置进行更新,并希望从该位置管理选择.

问题是,当我选择倒数第二个项目并将其删除时,所选项目将更新为最后一个项目(因为该项目已下移到该索引中).但是,DataGrid突出显示不会更新到该行.如果我打开行标题 可以看到行标题突出显示,但行未突出显示.如果我删除列表中的任何其他项目(包括最后一个项目),则突出显示效果很好.

我创建了一个小应用程序来复制此图像(请把松散的MVVM放在一起,仅用于演示).

XAML:

I can't figure out what is going wrong for this corner case. Basically, I have a DataGrid that is bound to an ObservableCollection in my view model. The SelectedItem of the DataGrid is also bound to a property in my view model. I then have a command that executes a delete operation on the selected item. I have also added an event handler for CollectionChanged so that I can be notified when an item has been removed from collection. In that event handler I update the selected item property to the item at the same index (or previous index if it was the last item). I do this in the collection changed event handler because the collection gets updated from a variety of places and want the selection to be managed from this one place.

The problem is that when I select the second to last item and delete it, the selected item is updated to the last item (since that item was shifted down into that index). But the DataGrid highlighting is not updated to that row. If I turn row headers on, I can see the row header is highlighted, but the row is not. The highlighting works fine if I delete any other item in the list, including the last item.

I created a small app that reproduces this (excuse the sloppy MVVM as I threw this together for demo only).

XAML:

     <DockPanel>
        <Button DockPanel.Dock="Bottom" Content="Remove" Command="{Binding DeleteCommand}" CommandParameter="{Binding}"  />
        <DataGrid DockPanel.Dock="Top" ItemsSource="{Binding People}" SelectedItem="{Binding SelectedPerson, Mode=TwoWay}">
            <DataGrid.RowStyle>
                <Style>
                    <Style.Resources>
                        <!--Forces the selection color to be the system highlight color when the item does not have focus-->
                        <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="{x:Static SystemColors.HighlightColor}" />
                    </Style.Resources>
                </Style>
            </DataGrid.RowStyle>
        </DataGrid>
    </DockPanel>

ViewModel:

ViewModel:

    public class ViewModel : INotifyPropertyChanged
	{
		public ViewModel()
		{
			People = new ObservableCollection<Person> { new Person("Jack"), new Person("Jill"), new Person("Jon"), new Person("Jane"), new Person("Joe") };
			People.CollectionChanged += PeopleOnCollectionChanged;
		}

		private ObservableCollection<Person> mPeople;
		public ObservableCollection<Person> People
		{
			get { return mPeople; }
			set
			{
				if (mPeople != value)
				{
					mPeople = value;
					OnPropertyChanged("People");
				}
			}
		}

		private Person mSelectedPerson;
		public Person SelectedPerson
		{
			get { return mSelectedPerson; }
			set
			{
				if (mSelectedPerson != value)
				{
					mSelectedPerson = value;
					OnPropertyChanged("SelectedPerson");
				}
			}
		}

		private DeleteCommand mDeleteCommand;
		public DeleteCommand DeleteCommand
		{
			get { return mDeleteCommand ?? (mDeleteCommand = new DeleteCommand()); }
		}

		private void PeopleOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
		{
			if (e.Action == NotifyCollectionChangedAction.Remove)
			{
				SelectedPerson = People.Count == 0 ? null : e.OldStartingIndex < People.Count ? People[e.OldStartingIndex] : People.Last();
			}
		}

		public event PropertyChangedEventHandler PropertyChanged;

		[NotifyPropertyChangedInvocator]
		protected virtual void OnPropertyChanged(string propertyName)
		{
			PropertyChangedEventHandler handler = PropertyChanged;
			if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
		}
	}


	public class Person
	{
		public string Name { get; set; }

		public Person(string name)
		{
			Name = name;
		}
	}

	public class DeleteCommand : ICommand
	{
		public void Execute(object parameter)
		{
			ViewModel viewModel = ((ViewModel) parameter);
			viewModel.People.Remove(viewModel.SelectedPerson);
		}

		public bool CanExecute(object parameter)
		{
			ViewModel viewModel = ((ViewModel)parameter);
			if (viewModel == null) return false;
			return viewModel.People.Count > 0 && viewModel.SelectedPerson != null;
		}

		public event EventHandler CanExecuteChanged
		{
			add { CommandManager.RequerySuggested += value; }
			remove { CommandManager.RequerySuggested -= value; }
		}
	}

推荐答案

我可以告诉您发生了什么,但是具体的解决方法取决于您.数据网格中所选项目的所选索引基于先前的内容.

I can tell you what is happening, but the exact fix will be up to you.  The selected index for the selected item in your datagrid is being based upon the previous content. 

因此,在您的特定情况下,如果先选择Jane然后将其删除,则确实将Joe设置为选定项,但是SelectedIndex属性设置为4,这当然不再存在,因为Joe的索引现在为3

So, in your specific case, if Jane is selected and then deleted, Joe is indeed be set as the selected item, but the SelectedIndex property is being set to 4, which of course no longer exists because Joe's index is now 3.

一种可能性是设置SelectedIndex而不是SelectedItem,因为事件处理程序中的所有计数似乎都具有正确的引用.

One potential is to set SelectedIndex, rather than SelectedItem, as all of the counts in your event handlers appear to have the proper references.


这篇关于WPF DataGrid.SelectedItem在移动到CollectionChanged事件处理程序中的最后一项时不会突出显示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆