如何绑定用户控件使用作为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).

我不明白为什么它不把数据绑定到用户控件

如何绑定用户控件使用作为datagridtemplatecolum列在WPF失败

DataGridRow具有Person对象的DataContextDataContext在您的VisualTree中继承,因此您的UC具有相同的上下文。要使您的示例工作:

  1. 扔掉UC中的BirthDayObjProperty
  2. DataGrid中删除这一行:DataContext="{Binding UpdateSourceTrigger=PropertyChanged}"
  3. 扔掉UC: DataContext="{Binding RelativeSource={RelativeSource Self}}"
  4. 中的这行
  5. 您的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>
    
  6. 阅读更多关于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>
相关文章:
  • 没有找到相关文章