I have created a custom control with a dependency property, but the PropertyChanged callback is not being triggered, and I cannot figure out why. Here is my XAML and code:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TexxtGridTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Text="{Binding InputText, UpdateSourceTrigger=PropertyChanged}" Margin="5"/>
<local:TextSplitterGrid Grid.Row="1" GridHeaders="{Binding SplitHeaders}" AutoGenerateColumns="False" Margin="5"/>
</Grid>
</Window>
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace TexxtGridTest
{
internal class ViewModel : INotifyPropertyChanged
{
private string _inputText;
private ObservableCollection<GridRowData> _splitHeaders = new ObservableCollection<GridRowData>();
public string InputText
{
get => _inputText;
set
{
if (_inputText != value)
{
_inputText = value;
SplitInputString();
OnPropertyChanged(nameof(InputText));
}
}
}
public ObservableCollection<GridRowData> SplitHeaders
{
get => _splitHeaders;
set
{
if (_splitHeaders != value)
{
_splitHeaders = value;
OnPropertyChanged(nameof(SplitHeaders));
}
}
}
void SplitInputString()
{
_splitHeaders.Clear();
var headers = _inputText.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var header in headers)
{
_splitHeaders.Add(new GridRowData { Header = header, Items = new ObservableCollection<string> { "aaa", "bbb" } });
}
OnPropertyChanged(nameof(SplitHeaders));
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class GridRowData : INotifyPropertyChanged
{
private string _header;
private ObservableCollection<string> _items { get; set; } = new ObservableCollection<string>();
public string Header { get => _header; set { if (_header != value) { _header = value; OnPropertyChanged(nameof(Header)); } } }
public ObservableCollection<string> Items { get => _items; set { if (_items != value) { _items = value; OnPropertyChanged(nameof(Items)); } } }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace TexxtGridTest
{
public class TextSplitterGrid : DataGrid
{
public ObservableCollection<GridRowData> GridHeaders
{
get { return (ObservableCollection<GridRowData>)GetValue(GridHeadersProperty); }
set { SetValue(GridHeadersProperty, value); }
}
public static readonly DependencyProperty GridHeadersProperty =
DependencyProperty.Register("GridHeaders", typeof(ObservableCollection<GridRowData>), typeof(TextSplitterGrid), new PropertyMetadata(null, OnGridHeadersChanged));
private static void OnGridHeadersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is TextSplitterGrid dataGrid)
{
dataGrid.GenerateColumns();
}
}
private void GenerateColumns()
{
Columns.Clear();
if (GridHeaders != null)
{
foreach (var header in GridHeaders)
{
var textColumn = new DataGridTextColumn
{
Header = header.Header
};
Columns.Add(textColumn);
}
}
}
}
}
I expected that when the GridHeaders property changes, the OnGridHeadersChanged callback would be triggered, which in turn would call the GenerateColumns method to update the DataGrid columns based on the new data.
Despite these implementations, the PropertyChanged callback for the GridHeaders dependency property does not seem to be triggered. What am I missing in the implementation that prevents the callback from being executed?