Если ваша сетка является одиночным выбором, я предлагаю вам использовать CollectionView в качестве ItemsSource вместо фактического ObservableCollection. Затем убедитесь, что для Datagrid.IsSynchronizedWithCurrentItem установлено значение true. Наконец, в конце вашей «логики замены элемента» просто переместите CurrentItem объекта CollectionView в соответствующий новый элемент.
Ниже приведен пример, демонстрирующий это. (Я использую здесь ListBox. Надеюсь, он отлично работает с вашим Datagrid).
РЕДАКТИРОВАТЬ - НОВЫЙ ОБРАЗЕЦ С ИСПОЛЬЗОВАНИЕМ MVVM:
1009 * XAML *
<Window x:Class="ContextTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="window"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<ListBox x:Name="lb" DockPanel.Dock="Left" Width="200"
ItemsSource="{Binding ModelCollectionView}"
SelectionMode="Single" IsSynchronizedWithCurrentItem="True">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Text="{Binding ElementName=lb, Path=SelectedItem.Description}"/>
</DockPanel>
</Window>
Code-Behind:
using System;
using System.Windows;
using System.Windows.Data;
using System.Collections.ObjectModel;
using System.Windows.Threading;
namespace ContextTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
public class ViewModel
{
private DataGenerator dataGenerator;
private ObservableCollection<Model> modelCollection;
public ListCollectionView ModelCollectionView { get; private set; }
public ViewModel()
{
modelCollection = new ObservableCollection<Model>();
ModelCollectionView = new ListCollectionView(modelCollection);
//Create models
for (int i = 0; i < 20; i++)
modelCollection.Add(new Model() { Name = "Model" + i.ToString(),
Description = "Description for Model" + i.ToString() });
this.dataGenerator = new DataGenerator(this);
}
public void Replace(Model oldModel, Model newModel)
{
int curIndex = ModelCollectionView.CurrentPosition;
int n = modelCollection.IndexOf(oldModel);
this.modelCollection[n] = newModel;
ModelCollectionView.MoveCurrentToPosition(curIndex);
}
}
public class Model
{
public string Name { get; set; }
public string Description { get; set; }
}
public class DataGenerator
{
private ViewModel vm;
private DispatcherTimer timer;
int ctr = 0;
public DataGenerator(ViewModel vm)
{
this.vm = vm;
timer = new DispatcherTimer(TimeSpan.FromSeconds(5),
DispatcherPriority.Normal, OnTimerTick, Dispatcher.CurrentDispatcher);
}
public void OnTimerTick(object sender, EventArgs e)
{
Random r = new Random();
//Update several Model items in the ViewModel
int times = r.Next(vm.ModelCollectionView.Count - 1);
for (int i = 0; i < times; i++)
{
Model newModel = new Model()
{
Name = "NewModel" + ctr.ToString(),
Description = "Description for NewModel" + ctr.ToString()
};
ctr++;
//Replace a random item in VM with a new one.
int n = r.Next(times);
vm.Replace(vm.ModelCollectionView.GetItemAt(n) as Model, newModel);
}
}
}
}
СТАРЫЙ ОБРАЗЕЦ:
XAML:
<Window x:Class="ContextTest.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">
<StackPanel>
<ListBox x:Name="lb" SelectionMode="Single" IsSynchronizedWithCurrentItem="True" SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Text="{Binding ElementName=lb, Path=SelectedItem.Name}"/>
<Button Click="Button_Click">Replace</Button>
</StackPanel>
</Window>
Код-за:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace ContextTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
ObservableCollection<MyClass> items;
ListCollectionView lcv;
public MainWindow()
{
InitializeComponent();
items = new ObservableCollection<MyClass>();
lcv = (ListCollectionView)CollectionViewSource.GetDefaultView(items);
this.lb.ItemsSource = lcv;
items.Add(new MyClass() { Name = "A" });
items.Add(new MyClass() { Name = "B" });
items.Add(new MyClass() { Name = "C" });
items.Add(new MyClass() { Name = "D" });
items.Add(new MyClass() { Name = "E" });
}
public class MyClass
{
public string Name { get; set; }
}
int ctr = 0;
private void Button_Click(object sender, RoutedEventArgs e)
{
MyClass selectedItem = this.lb.SelectedItem as MyClass;
int index = this.items.IndexOf(selectedItem);
this.items[index] = new MyClass() { Name = "NewItem" + ctr++.ToString() };
lcv.MoveCurrentToPosition(index);
}
}
}