Что
Сетка DataGrid связана с ObservableCollection во ViewModel.
Каждые 2 секунды, элемент поочередно модифицируется / добавляется.
Строка измененной / добавленной таблицы данных элементов выделяется на 1 секунду.
Проблема
Добавленный элемент должен быть вставлен по указанному индексу, а не обязательно в концеObservableCollection.Это достигается с помощью Insert(int index, ListItemVM item)
.
Ошибка
Элемент добавляется по индексу 1, на 2-й позиции.Пользовательский интерфейс обновляется соответствующим образом и выделяет новый элемент , НО ТАКЖЕ НЕПРАВИЛЬНО ВЫДЕРЖИВАЕТ ПОСЛЕДНИЙ ПУНКТ .Я действительно хотел бы избавиться от нежелательного поведения, и я не могу понять, как.
Код работает:
XAML
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<DataGrid ItemsSource="{Binding MyList}" AutoGenerateColumns="False" CanUserAddRows="False" GridLinesVisibility="None" HeadersVisibility="None" BorderThickness="0" ScrollViewer.VerticalScrollBarVisibility="Visible">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Background" Value="Green" />
<Style.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="00:00:01" Storyboard.TargetProperty="Background.Color" From="Blue" To="Transparent" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label>
<TextBlock Text="{Binding Id}" />
</Label>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label>
<TextBlock x:Name="txtTheData" Text="{Binding TheData, NotifyOnTargetUpdated=True}" Background="Transparent" />
</Label>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Window>
Код-за
using System.Windows;
using WpfApp1.ViewModels;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
DataContext = new MainWindowVM();
InitializeComponent();
}
}
}
ViewModel
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows.Threading;
namespace WpfApp1.ViewModels
{
public class MainWindowVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
Random random = new Random();
public ObservableCollection<ListItemVM> MyList { get; set; } = new ObservableCollection<ListItemVM>
{
new ListItemVM(1, "Data1"),
new ListItemVM(2, "Data2"),
new ListItemVM(3, "Data3"),
};
bool mustAdd;
public MainWindowVM()
{
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(2000);
timer.Tick += (object sender, EventArgs e) =>
{
mustAdd = !mustAdd;
if (mustAdd == false)
{
// Emulate Update existing
var nextData = new string(Enumerable.Repeat("ABCDEFG", 10).Select(s => s[random.Next(s.Length)]).ToArray());
MyList[1].SetNewData(nextData);
}
else
{
// Emulate Add new
var newItem = new ListItemVM(99, "old");
MyList.Insert(1, newItem);
// Notify the UI of the change
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MyList)));
newItem.SetNewData("NEW");
}
};
timer.Start();
}
}
}
Элемент ViewModel
using System.ComponentModel;
namespace WpfApp1.ViewModels
{
public class ListItemVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int Id { get; set; }
public string TheData { get; set; }
public ListItemVM(int id, string theData)
{
Id = id;
TheData = theData;
}
internal void SetNewData(string nextData)
{
// Change data
TheData = nextData;
// Notify the UI of the change
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TheData)));
}
}
}