Member 12606650 Ответов: 1

Элемент управления DataGrid, привязанный к коллекции concurrentqueue не обновляются как элементы добавляются


Я разрабатываю многопоточное приложение для мониторинга. В дополнение к "основному" потоку существует 2 набора потоков чтения-записи, соединяющихся с 2 экземплярами производственного приложения. Часть потока сообщений из производственных приложений-это элементы EvtMsg. Они помещаются потоком чтения в ConcurrentQueue для этой конкретной стороны (слева или справа). Главное окно имеет кнопку EvtMsg для каждой стороны. Когда вы нажмете на один из них, он вызовет окно, содержащее DataGrid, заполненный из данного ConcurrentQueue.

Проблема заключается в том, что когда я открываю окно EvtMsg, DataGrid заполняется всеми объектами EvtMsg, полученными до этого момента (скажем, например, 3 элемента), но при получении новых сообщений EvtMsg они не обновляют окно (я использую INotifyPropertyChanged, и я отладил, чтобы проверить, что ConcurrentQueue имеет новые элементы).

Данные структуры:
public enum eSide : int { LEFT = 0, RIGHT = 1 }
public const int C_numSides = 2;
// ....

public class EvtMsg : INotifyPropertyChanged
{
    public  ulong        sequenceNumber         { get; set; }
    public  string       description            { get; set; }
    // ....
}

public class AnEvtQueue : INotifyPropertyChanged
{
    public ConcurrentQueue<EvtMsg> EvtQueue { get; set; }

    public AnEvtQueue()
    {
        EvtQueue = new ConcurrentQueue<EvtMsg>();
    }
    // ....
}

public class EvtHandler : INotifyPropertyChanged
{
    public AnEvtQueue[]     Sides     {get; set;}

    public EvtHandler()
    {
        Sides = new AnEvtQueue[C_numSides];
        Sides[(int)eSide.LEFT ] = new AnEvtQueue();
        Sides[(int)eSide.RIGHT] = new AnEvtQueue();
    }
    // ....
    public void AddEvtMsg(eSide WhichSide, EvtMsg msg)
    {
        Sides[side].EvtQueue.Enqueue(msg);
    }
    // ....
}

код XAML:
<DataGrid Grid.Row="2"
          AutoGenerateColumns="False"
          IsReadOnly="True"
          SelectionMode="Single"
          SelectionUnit="FullRow"
          GridLinesVisibility="None"
          Name="StatList"
          ItemsSource="{Binding NotifyOnSourceUpdated=True}">
    <DataGrid.Columns>
        <!-- Col 0: Sequence # -->
        <DataGridTextColumn Binding="{Binding Path=sequenceNumber}"
                        ElementStyle="{StaticResource DGCell_RightAlignStyle}"
                        Header="Sequence #" />

        <!-- Col 0: EvtMsg Text -->
        <DataGridTextColumn Binding="{Binding Path=description}"
                            FontFamily="Courier New"
                            Header="EvtMsg Text" />
    </DataGrid.Columns>
</DataGrid>

<!--     ....     -->

С фоновым кодом:
    public EvtMsgWindow(eSide WhichSide)
    {
        public ApplicationViewModel AppVM = ApplicationViewModel.Instance;
        InitializeComponent();

        StatList.ItemsSource = AppVM.TheEvtHandler.Sides[(int)WhichSide].EvtQueue;
    }
}


Что я уже пробовал:

Я пробовал ObservableCollection, но это, похоже, не работало с несколькими потоками (socket thread добавляет, GUI thread читает).

Gerry Schmitz

Это не "казалось", чтобы работать не является причиной, чтобы отказаться от предпочтительного решения. Используйте многоголовый "прокси", если это необходимо.

1 Ответов

Рейтинг:
2

Richard Deeming

Чтобы WPF мог видеть изменения в коллекции, ему необходимо реализовать то INotifyCollectionChanged интерфейс[^].

Вы используете то ConcurrentQueue<T> класс[^], который не реализует этот интерфейс. Таким образом, WPF не будет получать уведомления при обновлении коллекции и не будет обновлять какие-либо связанные с ней элементы управления.

Вам либо нужно будет использовать ObservableCollection<T> и обеспечьте свою собственную блокировку для обеспечения потокобезопасности, или создайте свой собственный класс коллекции для обертывания ConcurrentQueue и поднимите руку. CollectionChanged событие, когда коллекция обновляется.