【问题标题】:Unable to properly data bind in WPF C#无法在 WPF C# 中正确进行数据绑定
【发布时间】:2013-10-30 22:12:01
【问题描述】:

我是 WPF 和数据绑定的新手,经过数小时的搜索和搜索 Stackoverflow,我无法找到一个全面的解决方案。我正在尝试使用 KinectWindow.xaml 上的数据绑定在 TextBlock 控件上显示文本:

 <TextBlock x:Name="InitText" 
            TextWrapping="Wrap" 
            Text="{Binding Source=ScanInitTextA, 
                           Path=ScanInitTextA, 
                           UpdateSourceTrigger=PropertyChanged}"

免费的 KinectWindow.xaml.cs 类具有以下属性:

string ScanInitText = "Preparing for Initial Scan.";    
 string ScanInitTextA
    { get { return (ScanInitText) ; }
        set { ScanInitTextA = value; }
    }

我做了很多尝试,要么直接从类绑定属性,要么从 xaml.xml 绑定属性。尝试做任何事情时,我通常会收到此错误:

System.Windows.Data Error: 40 : BindingExpression path error: 'ScanInitTextA' property not found on 'object' ''String' (HashCode=1828304777)'. 
BindingExpression:Path=ScanInitTextA; 
DataItem='String' (HashCode=1828304777); 
target element is 'TextBlock' (Name='InitText'); 
target property is 'Text' (type 'String')

据我了解,在对象字符串中找不到 ScanInitTextA?

最后,我知道当我从不同的类(不是 KinectWindow.xaml.cs,通过引用 xaml 中的类并将绑定源更改为该类的名称)尝试类似方法时,数据绑定确实有效,但出于其他原因,我更喜欢通过这个类来完成。

提前致谢。 :)

【问题讨论】:

  • 您的理解是正确的 - 请检查您的绑定。我认为你混淆了路径和来源。尝试删除 Source=ScanInitTextA

标签: c# wpf data-binding


【解决方案1】:

试试这个:

<TextBlock x:Name="InitText" 
                TextWrapping="Wrap" 
                Text="{Binding  Path=ScanInitTextA}"

错误消息表明您试图在字符串对象本身上查找属性ScanInitTextA。我认为当前TextBlockSource 是之前分配的(可能是DataContext)。

【讨论】:

  • 我最初尝试过,但它不起作用,因为我的代码中有一个 DataContext 用于其他东西(或者至少是我认为的),这就是我添加绑定源的原因。
【解决方案2】:

你试过了吗

     <TextBlock x:Name="InitText" 
        TextWrapping="Wrap" 
        Text="{Binding  Path=ScanInitTextA, 
                       UpdateSourceTrigger=PropertyChanged}"

【讨论】:

  • 是的,这就是我最初尝试的方法,但我有一个用于其他内容的数据上下文,所以我认为这就是它不起作用的原因。
【解决方案3】:

如果您已将您的视图的DataContext 设置为self,那么给Source 是错误的。只需将您的绑定更新为:

 <TextBlock x:Name="InitText" 
        TextWrapping="Wrap" 
        Text="{Binding Path=ScanInitTextA, 
                       UpdateSourceTrigger=PropertyChanged}"/>

【讨论】:

  • 这是我最初尝试的,但我得到了相同的输出错误。
【解决方案4】:

更新

需要一种绑定到主窗口属性的方法。这是一种实现绑定的方法

<Window x:Name="KinectWindow"
        Title="My Kinect Show"
        ...>
    <TextBlock Text="{Binding ScanInitTextA, ElementName=KinectWindow}" />

请注意,如果您希望 ScanInitTextA 的值会被某些东西更改并且需要自动显示更改,那么您仍然需要让 ScanInitTextA 执行属性更改通知。。请参阅下面的 #1 和 #2。


坚持MVVM类型系统并将VM放在Window的Data Context上的原始建议

  1. 首先,任何持有 ScanInitTextA 的类都需要实现 INotifyPropertyChanged 并将 ScanInitTextA 公开
  2. 其次,通过将页面的数据上下文设置为具有 INotifyPropertyChanged 的​​类来完成更好的绑定方法。这样做是因为它将所有数据集中显示在一个位置,并且页面的数据上下文由所有控件继承,因此此时页面的每个控件都简单地绑定到属性名称。这是基本 MVVM,其中 VM(视图模型)具有 INotifyPropertyChanged。

示例

我们想在我们的页面上的列表框中显示Members,一个字符串列表。最终我们的绑定将只是{Binding Members}

查看模型

public class MainVM : INotifyPropertyChanged 
{
 
    private List<string> _Members;
 
    public List<string> Members 
    { 
        get { return _Members; }
        set { _Members = value; OnPropertyChanged(); } 
    }
    public MainVM()
    {
        // Simulate Asychronous access, such as to a db.
 
        Task.Run(() =>
                    {
                        Members = new List<string>() {"Alpha", "Beta", "Gamma", "Omega"};
                        MemberCount = Members.Count;
                    });
    }
    /// <summary>Event raised when a property changes.</summary>
    public event PropertyChangedEventHandler PropertyChanged;
 
    /// <summary>Raises the PropertyChanged event.</summary>
    /// <param name="propertyName">The name of the property that has changed.</param>
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
 
}
}

页面代码隐藏

   public partial class MainWindow : Window
    {
 
        public MainVM ViewModel { get; set; }
 
        public MainWindow()
        {
            InitializeComponent();
 
            // Set the windows data context so all controls can have it.
            DataContext = ViewModel = new MainVM();
 
        }
 
    }

带有绑定的页面 Xaml

   <ListBox Name="lbData"
                ItemsSource="{Binding Members}"
                SelectionMode="Multiple"
                Margin="10" />

这个例子摘自我的博客文章:

Xaml: ViewModel Main Page Instantiation and Loading Strategy for Easier Binding.

【讨论】:

  • 您好,我忘记在此处包含它,但该属性已经公开并且 INotifyPropertyChanged 已经实现。我也会使用 datacontext,但我已经在使用 datacontext(或者更确切地说,Microsoft 示例的代码正在使用数据上下文来处理其他内容),这就是我尝试使用 source 的原因。
  • @Gaessaki 好的,在 MS 上使用数据上下文;无论当前数据上下文是什么,都使其包含 Microsoft 所需的属性和您所需的属性。没有规则说数据上下文只能具有一个属性。
  • 您有关于如何执行此操作的资源吗?如果我出于某种原因再次使用 datacontext,它似乎会覆盖 MS 的原始 datacontext 设置。
  • 这里是代码,如果它有任何帮助(取出适合 char lim 的行):public KinectWidow() { this.viewModel = new KinectWindowViewModel(); this.viewModel.KinectSensorManager = new KinectSensorManager(); Binding sensorBinding = new Binding("KinectSensor"); sensorBinding.Source = this; BindingOperations.SetBinding(this.viewModel.KinectSensorManager, KinectSensorManager.KinectSensorProperty, sensorBinding); this.DataContext = this.viewModel; InitializeComponent(); }
  • KinectWindowViewModel() 可以改变吗?
猜你喜欢
  • 1970-01-01
  • 2019-05-24
  • 1970-01-01
  • 2014-11-04
  • 1970-01-01
  • 1970-01-01
  • 2022-09-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多