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"/>