DataGrid не создает строки, когда обновляется его ItemSource, а иногда и повторяющиеся записи. - PullRequest
0 голосов
/ 18 мая 2018

Мы создаем приложение 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 Ответ

0 голосов
/ 18 мая 2018

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

Измените 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"/>
...