DataGrid не создает строки, когда обновляется его ItemSource, а иногда и повторяющиеся записи.

Мы создаем приложение WPF, которое использует FileSystemWatcher для мониторинга изменений в каталоге по выбору пользователя и выводит изменения в DataGrid. В моем конструкторе MainWindow() я связываю свою DataGrid со списком, который я вызываю _eventList через ItemSource.

Когда происходит событие OnChanged или OnRenamed FileSystemWatcher, мое приложение успешно записывает четыре набора строк (тип изменения, затронутый файл, путь, дата последнего изменения) в массив, который я вызываю, _event. Это составляет одно событие. Затем, после создания этого массива _event, я делаю бледную попытку обработать мой "Вызывающий поток не может получить доступ к этому объекту, потому что другой поток владеет им", исключая перекрестную многопоточность, вызывая отдельный метод с именем SetThreadSafe().

Вот где я верю, что все рушится для меня. Нежелательное поведение, происходящее в моем методе SetThreadSafe, заключается в том, что моя DataGrid показывает, что она содержит в своем свойстве Items записи, соответствующие каждому событию. Каждый индекс в DataGrid.Items привязан к синониму моего _eventList (как и должно быть), а внутри каждого индекса этого свойства List/Items находятся правильные значения в каждом индексе массива внутри.

Итак, во-первых, моя DataGrid показывает, что она содержит правильные данные в свойстве Items в моем отладчике, но строки не будут заполняться в моей DataGrid.

Во-вторых, иногда не все, метод SetThreadSafe запускает его, если И ИЛИ ДАЛЕЕ обуславливает оба условия, следовательно, добавляя дублирующую запись в мой DataGrid.Items/_eventList. Я больше не получаю исключение между потоками, но я чувствую, что здесь что-то явно отсутствует.

[ОБНОВЛЕНИЕ: Благодаря ASh, мой вопрос был решен. Я отредактировал мой код, чтобы отразить правильные настройки. Теперь все работает как надо.]

C#:

using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows;
using WinForms = System.Windows.Forms;

namespace EyeInTheSky
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml + backend code for FileSystemWatcher project
    /// </summary>
    public partial class MainWindow : Window
    {
        #region Fields
        private FileSystemWatcher _watcher;
        private string[] _event;
        private ObservableCollection<string[]> _eventList;
        private bool _on;
        #endregion

        #region class Constructor
        public MainWindow()
        {
            InitializeComponent();
            _eventList = new ObservableCollection<string[]>();
            DataGrid_DisplayOutput.ItemsSource = _eventList;
        }
        #endregion

        #region FileSystemWatcher Methods
        private void OnChanged(object source, FileSystemEventArgs e)
        {
            _event = new string[4];
            _event[0] = e.ChangeType.ToString();
            _event[1] = e.Name;
            _event[2] = e.FullPath;
            _event[3] = DateTime.Now.ToString();

            SetThreadSafe();
        }

        private void OnRenamed(object source, RenamedEventArgs e)
        {
            _event = new string[4];
            _event[0] = e.ChangeType.ToString();
            _event[1] = e.Name;
            _event[2] = e.OldFullPath;
            _event[3] = DateTime.Now.ToString();

            SetThreadSafe();
        }

        private delegate void SetCallback();
        private void SetThreadSafe()
        {
            if (!CheckAccess())
            {
                SetCallback d = new SetCallback(SetThreadSafe);
                Dispatcher.Invoke(d);
            }
            else
            {
                _eventList.Add(_event);
            }
        }
        #endregion

WPF XAML:

<DataGrid x:Name="DataGrid_DisplayOutput" Grid.Column="1" HorizontalAlignment="Left" Margin="22,11,0,0" Grid.RowSpan="4" VerticalAlignment="Top" Width="356" Height="392" IsTextSearchEnabled="True" RowBackground="#FFFFFAE8" AlternatingRowBackground="White" HeadersVisibility="Column" AlternationCount="1" SelectionMode="Single" IsReadOnly="True">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding [0]}" Header="Change" Width="89" IsReadOnly="True"/>
        <DataGridTextColumn Binding="{Binding [1]}" Header="Change" Width="89" IsReadOnly="True"/>
        <DataGridTextColumn Binding="{Binding [2]}" Header="Change" Width="89" IsReadOnly="True"/>
        <DataGridTextColumn Binding="{Binding [3]}" Header="Change" Width="89" IsReadOnly="True"/>
    </DataGrid.Columns>
</DataGrid>

1 ответ

Решение

В коде есть несколько мест, которые нужно исправить

+ Изменить List<string[]> в ObservableCollection<string[]> исправить "строки не будут заполняться в моей DataGrid." проблема. В отличие от List, ObservableCollection может уведомлять пользовательский интерфейс, когда элементы добавляются / удаляются.

_event создается только один раз _event = new string[4]; в конструкторе. Это означает, что у вас есть только 1 массив, и вы добавляете его несколько раз и стираете значения при выполнении изменения / переименования. Я полагаю, вам нужно создать новый массив в OnChanged/OnRenamed

ни один из DataGridTextColumn не имеет настроенного атрибута "Binding". поскольку каждая строка в DataGrid отображает массив, привязки должны использовать индексы:

<DataGridTextColumn Binding="{Binding [0]}" Header="Change" Width="89" IsReadOnly="True"/>
<DataGridTextColumn Binding="{Binding [1]}" Header="File" Width="89" IsReadOnly="True"/>
Другие вопросы по тегам