I want to use an User control from a different assembly as DataGridTemplateColumn. I've already looked at a lot of examples and questions, like this, this, this and this. I can't figure out why my code's not working. Here it is:
<Window x:Class="WpfTemplatesDemo3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:extraUserControl="clr-namespace:Templates;assembly=Templates"
xmlns:wpfTemplatesDemo3="clr-namespace:WpfTemplatesDemo3"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid x:Name="TableDataGrid" DataContext="{Binding UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Width="*"/>
<DataGridTextColumn Binding="{Binding Age}" Width="*"/>
<DataGridTextColumn Binding="{Binding Description}" Width="2*"/>
<DataGridTemplateColumn Width="3*" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<extraUserControl:BirthDateControl BirthDayObj="{Binding BirthDay, ElementName=TableDataGrid}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
namespace WpfTemplatesDemo3
{
public partial class MainWindow : Window
{
public ObservableCollection<Person> Persons { get;set; }
public MainWindow()
{
InitializeComponent();
this.populatePersons();
this.TableDataGrid.ItemsSource = this.Persons;
}
private void populatePersons()
{
this.Persons = new ObservableCollection<Person>();
Persons.Add(new Person { Age = 10, Name = "John0", BirthDay = new BirthDate(1, 2, 3) });
Persons.Add(new Person { Age = 11, Name = "John1", BirthDay = new BirthDate(2, 3, 4) });
Persons.Add(new Person { Age = 12, Name = "John2", BirthDay = new BirthDate(3, 4, 5) });
Persons.Add(new Person { Age = 13, Name = "John3", BirthDay = new BirthDate(4, 5, 6) });
Persons.Add(new Person { Age = 14, Name = "John4", BirthDay = new BirthDate(5, 6, 7) });
Persons.Add(new Person { Age = 15, Name = "John5", BirthDay = new BirthDate(6, 7, 8) });
}
}
}
<UserControl x:Class="Templates.BirthDateControl"
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"
mc:Ignorable="d" d:DesignWidth="300" Height="52.273"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
>
<Grid>
<StackPanel>
<Label Content="Date:"/>
<StackPanel Orientation="Horizontal" >
<TextBox Text="{Binding BirthDayObj.Day}" />
<TextBox Text="{Binding BirthDayObj.Month}"/>
<TextBox Text="{Binding BirthDayObj.Year}" />
</StackPanel>
</StackPanel>
</Grid>
</UserControl>
namespace Templates
{
public partial class BirthDateControl : System.Windows.Controls.UserControl
{
public static DependencyProperty BirthDayObjProperty =
DependencyProperty.Register("BirthDayObj", typeof(BirthDate), typeof(BirthDateControl));
public BirthDate BirthDayObj
{
get
{
return ((BirthDate)GetValue(BirthDayObjProperty));
}
set
{
SetValue(BirthDayObjProperty, value);
}
}
public BirthDateControl()
{
InitializeComponent();
}
}
}
namespace Entities
{
public class Person : INotifyPropertyChanged
{
private string name;
private int age;
private BirthDate _birthDay;
public string Name
{
get { return this.name; }
set {
this.name = value;
this.OnPropertyChanged("Name");
this.OnPropertyChanged("Description");
}
}
public int Age
{
get { return this.age; }
set
{
this.age = value;
this.OnPropertyChanged("Age");
this.OnPropertyChanged("Description");
}
}
public string Description
{
get { return Name + "_" + Age + "_" + BirthDay.Day; }
}
public BirthDate BirthDay
{
get { return this._birthDay; }
set
{
this._birthDay = value;
this.OnPropertyChanged("BirthDate");
this.OnPropertyChanged("Description");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(
this, new PropertyChangedEventArgs(propName));
}
}
}
namespace Entities
{
public class BirthDate : INotifyPropertyChanged
{
private int day;
private int month;
private int year;
public BirthDate(int day, int month, int year)
{
this.day = day;
this.month = month;
this.year = year;
}
public int Day {
get { return this.day; }
set
{
this.day = value;
this.OnPropertyChanged("day");
}
}
public int Month {
get { return this.month; }
set
{
this.month = value;
this.OnPropertyChanged("month");
}
}
public int Year {
get { return this.year; }
set
{
this.year = value;
this.OnPropertyChanged("year");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(
this, new PropertyChangedEventArgs(propName));
}
}
}
If I run it, it will show the columns, but the birthdate columns are empty.
There are no errors or warnings, but this shows up in Output:
System.Windows.Data Error: 40 : BindingExpression path error: 'BirthDay' property not found on 'object' ''DataGrid' (Name='TableDataGrid')'. BindingExpression:Path=BirthDay; DataItem='DataGrid' (Name='TableDataGrid'); target element is 'BirthDateControl' (Name=''); target property is 'BirthDayObj' (type 'BirthDate')
System.Windows.Data Error: 40 : BindingExpression path error: 'BirthDay' property not found on 'object' ''DataGrid' (Name='TableDataGrid')'. BindingExpression:Path=BirthDay; DataItem='DataGrid' (Name='TableDataGrid'); target element is 'BirthDateControl' (Name=''); target property is 'BirthDayObj' (type 'BirthDate')
System.Windows.Data Error: 40 : BindingExpression path error: 'BirthDay' property not found on 'object' ''DataGrid' (Name='TableDataGrid')'. BindingExpression:Path=BirthDay; DataItem='DataGrid' (Name='TableDataGrid'); target element is 'BirthDateControl' (Name=''); target property is 'BirthDayObj' (type 'BirthDate')
System.Windows.Data Error: 40 : BindingExpression path error: 'BirthDay' property not found on 'object' ''DataGrid' (Name='TableDataGrid')'. BindingExpression:Path=BirthDay; DataItem='DataGrid' (Name='TableDataGrid'); target element is 'BirthDateControl' (Name=''); target property is 'BirthDayObj' (type 'BirthDate')
System.Windows.Data Error: 40 : BindingExpression path error: 'BirthDay' property not found on 'object' ''DataGrid' (Name='TableDataGrid')'. BindingExpression:Path=BirthDay; DataItem='DataGrid' (Name='TableDataGrid'); target element is 'BirthDateControl' (Name=''); target property is 'BirthDayObj' (type 'BirthDate')
System.Windows.Data Error: 40 : BindingExpression path error: 'BirthDay' property not found on 'object' ''DataGrid' (Name='TableDataGrid')'. BindingExpression:Path=BirthDay; DataItem='DataGrid' (Name='TableDataGrid'); target element is 'BirthDateControl' (Name=''); target property is 'BirthDayObj' (type 'BirthDate')
'WpfTemplatesDemo3.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\UIAutomationTypes\v4.0_4.0.0.0__31bf3856ad364e35\UIAutomationTypes.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
System.Windows.Data Error: 40 : BindingExpression path error: 'BirthDay' property not found on 'object' ''DataGrid' (Name='TableDataGrid')'. BindingExpression:Path=BirthDay; DataItem='DataGrid' (Name='TableDataGrid'); target element is 'BirthDateControl' (Name=''); target property is 'BirthDayObj' (type 'BirthDate')
The program '[16364] WpfTemplatesDemo3.exe: Managed (v4.0.30319)' has exited with code 0 (0x0).
I can't figure out why it won't bind the data to the user control.
The DataGridRow has the DataContext of Person object. The DataContext is inherited among your VisualTree, thus your UC has the same context. To make your sample work:
BirthDayObjProperty from your UC.DataGrid: DataContext="{Binding UpdateSourceTrigger=PropertyChanged}"DataContext="{Binding RelativeSource={RelativeSource Self}}"Your UC bindings can be as simple as:
<Grid>
<StackPanel>
<Label Content="Date:"/>
<StackPanel Orientation="Horizontal" >
<TextBox Text="{Binding BirthDay.Day}" />
<TextBox Text="{Binding BirthDay.Month}"/>
<TextBox Text="{Binding BirthDay.Year}" />
</StackPanel>
</StackPanel>
</Grid>
Read more about DataContext inheritance and bindings in general,
as you're obviously misusing them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With