WPF ObservableCollection Вставить в индекс и NotifyOnTargetUpdated - PullRequest
0 голосов
/ 24 сентября 2019

Что

Сетка 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)));
        }
    }
}

1 Ответ

0 голосов
/ 24 сентября 2019

Как насчет того, чтобы вместо запуска анимации подсветки на Binding.TargetUpdated вы устанавливали свойство в ViewModel, например

private bool _shouldHighlight = false;
public bool ShouldHighlight
{
    get => _shouldHighlight;
    set
    {
        _shouldHighlight = value;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ShouldHighlight)));
    }
}

Когда вы добавляете элемент в коллекцию, в первую очередь он устанавливается для всехэлементы ShouldHighlight = false, затем добавьте элемент со значением ShouldHighlight = true.

В представлении вместо

                <EventTrigger RoutedEvent="Binding.TargetUpdated">
                    <BeginStoryboard>
                        ...
                </EventTrigger>
            </Style.Triggers>

вы можете использовать DataTrigger с Binding, для которого установлено значение ShouldHighlight и Value = True.Или подпишитесь на событие PropertyChanged объекта DataContext (в событии Loaded xaml.cs) и запустите анимацию выделения, когда аргументы PropertyChanged показывают изменение в mustHighlight на true:

Loaded += delegate
{
    if (DataContext is ListItemVM viewModel)
    {
        viewModel.PropertyChanged += delegate (object o, PropertyChangedArgs args)
        {
             if (args.PropertyName == nameof(viewModel.ShouldHighlight) && viewModel.ShouldHighlight)
                 // Starts the animation //
        }
    }
}

Я просто догадываюсь, дайте мне знатьесли это работает:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...