【问题标题】:Binding error with ListView, UserControl, DependencyProperty, ObservableCollection, INotifyPropertyChangedListView、UserControl、DependencyProperty、ObservableCollection、INotifyPropertyChanged 的​​绑定错误
【发布时间】:2012-04-15 16:34:00
【问题描述】:

我的绑定不起作用。我搜索了错误,但我不明白如何在我的情况下修复它。

System.Windows.Data 错误:1:无法创建默认转换器以在类型“MyApplication.MyUserControl”和“MyApplication.Person”之间执行“单向”转换。考虑使用 Binding 的 Converter 属性。绑定表达式:路径=; DataItem='MyUserControl' (Name='');目标元素是'MyUserControl'(名称='');目标属性是“PersonInfo”(类型“Person”)

System.Windows.Data 错误:5:BindingExpression 生成的值对目标属性无效。; Value='MyApplication.MyUserControl' BindingExpression:Path=; DataItem='MyUserControl' (Name='');目标元素是'MyUserControl'(名称='');目标属性是“PersonInfo”(类型“Person”)

基本上它是一个绑定到 Person 类的 ObservableCollection 的 ListView。

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public ObservableCollection<Person> PersonCollection { set; get; }

    public MainWindow()
    {
        PersonCollection = new ObservableCollection<Person>();
        InitializeComponent();
        PersonCollection.Add(new Person() { Name = "Bob", Age = 20 });
    }
}

MainWindow.xaml

<Window DataContext="{Binding RelativeSource={RelativeSource Self}}" xmlns:self="clr-namespace:MyApplication" x:Class="MyApplication.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ListView ItemsSource="{Binding PersonCollection}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <self:MyUserControl PersonInfo="{Binding}" />
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>
</Window>

MyUserControl.xaml.cs

public partial class MyUserControl : UserControl
{
    public static readonly DependencyProperty PersonProperty = DependencyProperty.Register("PersonInfo", typeof(Person), typeof(MyUserControl));

    public Person PersonInfo
    {
        get { return (Person)GetValue(PersonProperty); }
        set { SetValue(PersonProperty, value); }
    }

    public MyUserControl()
    {
        InitializeComponent();
    }
}

MyUserControl.xaml

<UserControl DataContext="{Binding RelativeSource={RelativeSource Self}}" x:Class="MyApplication.MyUserControl" 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">
<TextBlock Text="{Binding PersonInfo.Name}" />
</UserControl>

Person.cs

public class Person : INotifyPropertyChanged
{
    public int Age { set; get; }
    public string Name { set; get; }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(info));
    }
}

【问题讨论】:

    标签: c# wpf xaml binding


    【解决方案1】:

    我不太明白你为什么要把它弄得那么复杂。您可以在没有 PersonInfo 属性且不修改其 DataContext 的情况下轻松绑定您的 UserControl。

    <UserControl x:Class="MyApplication.MyUserControl" 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"> 
        <TextBlock Text="{Binding Name}" /> 
    </UserControl>
    

    然后将 UserControl 放置在 DataTemplate 中,无需显式绑定。它的 DataContext 将已经包含一个 Person 对象。

    <DataTemplate>      
        <StackPanel>      
            <self:MyUserControl />      
        </StackPanel>      
    </DataTemplate>      
    

    【讨论】:

      【解决方案2】:

      虽然您解决了问题,但您的整个 Binding 代码对我来说似乎是错误的,所以我提出了这个替代方案:

      拥有所有绑定源对象的基类 - ObservableObject.cs

      public abstract class ObservableObject : INotifyPropertyChanged
      {
          public event PropertyChangedEventHandler PropertyChanged;
      
          protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
          {
              var handler = this.PropertyChanged;
              if (handler != null)
                  handler(this, e);
          }
      
          protected void SetValue<T>(ref T field, T value, string propertyName)
          {
              if (!EqualityComparer<T>.Default.Equals(field, value))
              {
                  field = value;
                  this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
              }
          }
      }
      

      为您的 MainWindow 提供一个视图模型 - MainWindowModel.cs

      public class MainWindowModel : ObservableObject
      {
          private readonly ObservableCollection<Person> personCollection = new ObservableCollection<Person>()
          {
              new Person() { Name = "Bob", Age = 20 }
          };
      
          public ObservableCollection<Person> PersonCollection
          {
              get { return this.personCollection; }
          }
      }
      

      MainWindow.xaml.cs 现在基本上是空的。

      public partial class MainWindow : Window
      {
          public MainWindow()
          {
              InitializeComponent();
          }
      }
      

      MainWindow.xaml 将 DataContext 设置为新的 MainWindowModel 实例。

      <Window x:Class="MyApplication.MainWindow" 
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:self="clr-namespace:MyApplication">
          <Window.DataContext>
              <self:MainWindowModel/>
          </Window.DataContext>
          <ListView ItemsSource="{Binding PersonCollection}">
              <ListView.ItemTemplate>
                  <DataTemplate>
                      <StackPanel>
                          <self:MyUserControl/>
                      </StackPanel>
                  </DataTemplate>
              </ListView.ItemTemplate>
          </ListView>
      </Window>
      

      MyUserControl.xaml.cs 也基本上是空的(仅包含自动生成的代码)。

      public partial class MyUserControl : UserControl
      {
          public MyUserControl()
          {
              InitializeComponent();
          }
      }
      

      MyUserControl.xaml

      <UserControl x:Class="MyApplication.MyUserControl" 
                   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
                   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
          <TextBlock Text="{Binding Name}"/>
      </UserControl>
      

      Person.cs

      public class Person : ObservableObject
      {
          private int age;
          private string name;
      
          public int Age
          {
              get { return this.age; }
              set { this.SetValue(ref this.age, value, "Age"); }
          }
      
          public string Name
          {
              get { return this.name; }
              set { this.SetValue(ref this.name, value, "Name"); }
          }
      }
      

      【讨论】:

      • 非常好!感谢您改进我的代码并帮助我变得更好,感谢!
      【解决方案3】:

      将您的 UserControl XAML 更改为

      <UserControl x:Class="MyApplication.MyUserControl"
                   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">
          <TextBlock DataContext="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}"
                     Text="{Binding PersonInfo.Name}" />
      </UserControl>
      

      这里是 good explanation,用于解决 DataContext 的问题。

      【讨论】:

      • 查看我添加的链接以进行进一步调查。
      猜你喜欢
      • 1970-01-01
      • 2016-05-13
      • 2014-05-03
      • 2012-06-06
      • 2013-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多