Home > Software design >  How do I bind a listbox to the property of a property using MVVM?
How do I bind a listbox to the property of a property using MVVM?

Time:02-25

I am trying to populate a listbox with a bunch of serial data. I am saving the data to an ObservableCollection named SerialData (SerialData is type SerialMessage, a class that contains a bunch of data including 2 strings, time stamp and Message that I want to display). The ObservableCollection is a member of the DataCollector class. In the MainWindowViewModel I have declared the DataCollector and made it public. In my MainWindow the datacontext is set to MainWindowViewModel.

I want to bind the SerialData to a listbox on the MainWindow where I display the timestamp and message. I have tried several methods of binding the path to the SerialData but it does not show up in the listbox. I have confirmed that SerialData is updated correctly.

Is it possible to bind to the property of a property and display it's members?

My Code snippets:

SerialMessage class

    ...
    /// <summary>
    /// The time the message was received
    /// </summary>
    public DateTime TimeRecived
    {
        get;
        set;
    }

    /// <summary>
    /// The message on the serial bus
    /// </summary>
    public String Message
    {
        get;
        set;
    }
    ...

Mainwindow

...
<Window.DataContext>
    <local:MainWindowViewModel/>
</Window.DataContext>
...
    <ListView Grid.Column="0" Grid.Row="1" Name="MessageList" Margin="10" ItemsSource="{Binding Path=DC.SerialData}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding TimeRecived, StringFormat=dd-MM-yyyy HH:mm:ss.fff}"></TextBlock>
                    <TextBlock Text="{Binding Message}" Margin="10,0,0,0"></TextBlock>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListView>
    ...

MainWindowViewModel

    ...
    /// <summary>
    /// Instance of data collector
    /// </summary>
    public DataCollector DC
    {
        get
        {
            return m_dataCollector;
        }
    }
    ...

DataCollector Class

    ...
    /// <summary>
    /// All of the Data recived on the serial Bus as it comes in
    /// </summary>
    public ObservableCollection<SerialMessage> SerialData
    {
        get;
        private set;
    }
    ...

CodePudding user response:

There's nothing obviously wrong with your XAML, so the first place I'd check is how the components are being instantiated. Does your view model have the instance of the DataCollector that it expects? How does MainWindowViewModel get the DataCollector?

CodePudding user response:

There could be several reasons for not seeing the collection data. One possibility is a missing notification.

If you assign a value to the SerialData collection after the initial XAML loading routines have finished, your view won't notice that you've set SerialData later on.

You need to raise INotifyPropertyChanged.PropertyChanged in the setter to notify the view of the property change.

class DataCollector : INotifyPropertyChanged {
    ...
    public event PropertyChangedEventHandler PropertyChanged;
    ...
    private ObservableCollection<SerialMessage> _serialData;
    ....
    //somewhere some line code assigns to SerialData

    SerialData = GetSerialData();

    /// <summary>
    /// All of the Data recived on the serial Bus as it comes in
    /// </summary>
    public ObservableCollection<SerialMessage> SerialData
    {
        get => _serialData;
        private set {
           if (value != _serialData)
           {
                _serialData = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventsArgs(nameof (SerialData)));
           }
    }
  • Related