'How to make property change reflect in UI with C# WPF XAML

In my WPF application I would like to display a list of buttons when a list of documents are generated in the application based on user action. In my main xaml file: MainDocumentScanView.xaml I have:

<ItemsControl Grid.Row="1"
                ItemsSource="{Binding DocDataItemsViewModel.DocDataButtons, Mode=OneWay}" 
                HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <controls:DocDataButtonControl HorizontalAlignment="Left" VerticalAlignment="Top"
                        HeaderText="{Binding DocData.Nume}"
                        ExecuteCommand="{Binding StartScanDocumentCommand}"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel IsItemsHost="True"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

ScanningViewModel.cs

namespace mynamespace.ViewModels
{
    class ScanningViewModel : BindableBase
    {
        public DocDataItemsViewModel DocumentDataItems { get; private set; }
    
        public ScanningViewModel()
        {
            DocumentDataItems = new DocDataItemsViewModel();
        }
    
        private void OnDocDataCallback(List<DocData> items)
        {
            DocumentDataItems.SetDocData(items);
        }
    }
}

DocDataItemsViewModel.cs

using mynamespace.Models;
using Prism.Mvvm;
using System.Collections.Generic;
using System.Linq;
    
namespace mynamespace.ViewModels
{
    class DocDataItemsViewModel : BindableBase
    {
        #region Members
        private const string LogFileName = "DocDataItemsViewModel";
        private List<DocData> _docDataItems;
        private List<DocDataButtonViewModel> _docDataButtons;
        #endregion Members
    
        #region Properties
        public List<DocDataButtonViewModel> DocDataButtons
        {
            get { return _docDataButtons; }
            private set
            {
                _docDataButtons = value;
                RaisePropertyChanged("DocDataButtons");
             }
        }
   
        #endregion Properties
    
        #region Constructor
        public DocDataItemsViewModel(List<DocData> docDataItems) : this()
        {
            SetDocData(docDataItems);
        }
    
        public DocDataItemsViewModel()
        {
            _docDataItems = new List<DocData>();
        }
    
        #endregion Constructor
   
        #region Methods
    
        public void SetDocData(List<DocData> data)
        {
            LoggerManager.Instance.Info(LogFileName, "Setting new scanned data.");
            _docDataItems = data;
    
            DocDataButtons = data
                .OrderBy(d => d.Name)
                .Select(d => new DocDataButtonViewModel(d))
                .ToList();
        }
   
        #endregion Methods
    }
}

DocDatButtonViewModel.cs

using mynamespace.Models;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
    
namespace mynamespace.ViewModels
{
    class DocDataButtonViewModel : BindableBase
    {
        #region Members
        private const string LogFileName = "DocDataButtonViewModel";
        private Boolean _isSelected;
        #endregion Members
    
        #region Properties
    
        public DocData DocData { get; private set; }
    
        public Boolean IsSelected
        {
            get { return _isSelected; }
            set
            {
                if (_isSelected != value)
                {
                    _isSelected = value;
                    RaisePropertyChanged("IsSelected");
                }
            }
        }
    
        #endregion Properties
    
        #region Constructor
        public DocDataButtonViewModel(DocData docData)
        {
            DocData = docData;
        }
        #endregion Constructor
    }
}

DocDataButtonControl.xaml

<UserControl x:Class="mynamespace.Controls.DocDataButtonControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:mynamespace.Controls"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">

    <UserControl.Resources>
        <Style TargetType="Border" x:Key="HoverBorderStyle">
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Setter Property="Background" Value="Transparent"/>
            <Style.Triggers>
                <Trigger Property="Border.IsMouseOver" Value="True">
                    <Setter Property="Border.BorderBrush" Value="White" />
                    <Setter Property="Border.Background" Value="{Binding HoverBrushColor, ElementName=uc}"/>
                </Trigger>
            </Style.Triggers>
        </Style>

        <Style TargetType="StackPanel" x:Key="NoImageStackPanelStyle">
            <Setter Property="Margin" Value="10,50"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding NoImage, ElementName=uc}" Value="true">
                    <Setter Property="Margin" Value="10"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </UserControl.Resources>

    <Border BorderThickness="0" VerticalAlignment="Top"
            HorizontalAlignment="Stretch"
            Style="{StaticResource HoverBorderStyle}">

        <StackPanel IsHitTestVisible="False" Style="{StaticResource NoImageStackPanelStyle}">
            <TextBlock Text="{Binding HeaderText, ElementName=uc}" 
                       HorizontalAlignment="Center"
                       FontSize="15" Foreground="{Binding GeneralColor, ElementName=uc}"/>
        </StackPanel>
    </Border>
</UserControl>

DocData.cs

using System;
    
namespace mynamespace.Models
{
    class DocData
    {
        public String Name { get; set; }
    }
}

SetDocData() is called from a different viewmodel with a list of DocData. There is no complilation or runtime error. I tried changing the DataTemplate in MainDocumentScanView.xaml to display a static TextBlock to check that the problem is not with my DocDataButtonControl, but the TextBlock was not displayed either.

What am I missing here to make the data change update the UI properly?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source