如何绑定用户控件使用作为datagridtemplatecolum列在WPF失败
本文关键字:datagridtemplatecolum 列在 失败 WPF 控件 何绑定 绑定 用户 | 更新日期: 2023-09-27 18:05:25
我想使用来自不同程序集的用户控件作为DataGridTemplateColumn。我已经看了很多例子和问题,比如这个,这个,这个和这个。我不明白为什么我的代码不工作。
MainWindow.xaml
<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>
MainWindow.xaml.cs
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) });
}
}
}
BirthDateControl.xaml
<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>
BirthDateControl.xaml.cs
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();
}
}
}
Person.cs
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));
}
}
}
BirthDate.cs
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));
}
}
}
如果我运行它,它将显示列,但是birthdate列是空的。
没有错误或警告,但这显示在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).
我不明白为什么它不把数据绑定到用户控件
DataGridRow
具有Person
对象的DataContext
。DataContext
在您的VisualTree
中继承,因此您的UC具有相同的上下文。要使您的示例工作:
- 扔掉UC中的
BirthDayObjProperty
。 - 从
DataGrid
中删除这一行:DataContext="{Binding UpdateSourceTrigger=PropertyChanged}"
- 扔掉UC:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
中的这行 您的UC绑定可以像以下这样简单:
<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>
阅读更多关于
DataContext
继承和绑定的一般信息,
你必须删除DataContext="{Binding RelativeSource={RelativeSource Self}}"在你的usercontrol和使用eg ElementName绑定。否则将破坏继承
的数据上下文。<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"
x:Name="uc"
>
<Grid>
<StackPanel>
<Label Content="Date:"/>
<StackPanel Orientation="Horizontal" >
<TextBox Text="{Binding ElementName=uc, Path=BirthDayObj.Day}" />
<TextBox Text="{Binding ElementName=uc, Path=BirthDayObj.Month}"/>
<TextBox Text="{Binding ElementName=uc, Path=BirthDayObj.Year}" />
</StackPanel>
</StackPanel>
</Grid>
</UserControl>
和你的DataGridTemplateColumn不需要一个"新的"数据上下文,因为生日属性在你的person对象
<DataGridTemplateColumn Width="3*" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<extraUserControl:BirthDateControl BirthDayObj="{Binding BirthDay}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>