C#WPF数据绑定-数据未更新

时间:2018-07-05 16:10:03

标签: c# wpf data-binding

这里有几个“ WPF数据绑定未更新”问题,我已经通读了所有这些问题,包括排名最高的一个: WPF DataBinding not updating?

但是,在这种情况下,我要交换整个对象,更糟糕的是,当我尝试创建自己正在做的事情的可复制版本时,它可以在该版本中工作:

<Window x:Class="WpfApp2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp2"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <Label Content="Contact Address" />
        <TextBox x:Name="txtContactAddress" Text="{Binding Path=Contact.Address, Mode=OneWay}" />
        <Label Content="Organization Address" />
        <TextBox x:Name="txtOrgAddress" Text="{Binding Path=Organization.Address, Mode=OneWay}" />
        <Button Content="Next Contact" Click="Button_Click" />
    </StackPanel>
</Window>

隐藏代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public RecordWrapper CurrentRecord;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            CurrentRecord = new RecordWrapper(new ContactData());
            this.DataContext = CurrentRecord;
        }
    }

    public class RecordWrapper : INotifyPropertyChanged
    {
        private ContactData _Contact;
        public ContactData Contact
        {
            get { return _Contact;  }
            set
            {
                _Contact = value;
                OnPropertyChanged("Contact");
                Organization = _Contact.Organization;
            }
        }
        private OrganizationData _Organization;
        public OrganizationData Organization
        {
            get { return _Organization; }
            set
            {
                _Organization = value;
                OnPropertyChanged("Organization");
            }
        }

        public RecordWrapper(ContactData contactData)
        {
            Contact = contactData;
        }

        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
        #endregion
    }

    public class ContactData
    {
        public string Address { get; set; }
        public OrganizationData Organization { get; set; }

        public ContactData()
        {
            Address = new Random().Next(1000, 9999) + " Contact Street";
            Organization = new OrganizationData();
        }
    }

    public class OrganizationData
    {
        public string Address { get; set; }
        public OrganizationData()
        {
            Address = new Random().Next(1000, 9999) + " Org Street";
        }
    }
}

因此,此特定示例按预期方式工作-当我单击“下一个联系人”按钮时,它将生成一个新的RecordWrapper对象,其中包含一个新的ContactData和新的OrganizationData对象,然后将该新对象分配给DataContext,然后我看到文本框会正确更新。

由于我要替换DataContext中的整个对象,因此我什至可以放弃属性通知,并将RecordWrapper减小为:

public class RecordWrapper
{
    public ContactData Contact { get; set; }
    public OrganizationData Organization { get; set; }

    public RecordWrapper(ContactData contactData)
    {
        Contact = contactData;
        Organization = Contact.Organization;
    }
}

...而且效果仍然很好。

但是,我的真实代码反映了第一个示例。

在实际代码中,似乎无法使用新对象更新this.DataContext。什么都没有更新,但是也没有错误。在XAML中设置路径也不起作用。实际上,使它起作用的唯一方法是使用代码隐藏直接将绑定设置为数据对象:

BindingOperations.SetBinding(txtContactAddress, TextBox.TextProperty, new Binding() { Source = this.RecordWrapper, Path = new PropertyPath("Contact.Address"), Mode = BindingMode.OneWay });

当我这样做时,我可以看到它正在工作,但是如果我每次必须在每个字段上运行代码以更新绑定,那显然是缺少绑定点。

我很困惑,因为除了具有更多字段,不同的字段名称以及与数据或绑定无关的差异之外,实际代码与示例几乎相同。当我单击一个按钮时,这是确切的代码:

this.Data = new DataBindings(CurrentContact.FetchFake());
this.DataContext = this.Data;

FetchFake()方法生成带有一些虚假数据的新CurrentContact对象,并且我已经验证了第一行运行之后,填充了this.Data.CurrentContact.Login,并且是CurrentContact对象的只读属性(不是字段)。

...和一个XAML文本框如下所示:

<TextBox x:Name="txtAccountNumber" Grid.Column="1" Grid.Row="1"  Width="Auto" Text="{Binding Path=CurrentContact.Login, Mode=OneWay}"/>

结果为空白。我还尝试了顺序上的变化(例如,首先将DataContext设置为this.Data,然后设置this.Data.CurrentContact属性,让属性已更改的通知启动,但仍然没有运气。但是如果我运行:

BindingOperations.SetBinding(tabAccount.txtAccountNumber, TextBox.TextProperty, new Binding() { Source = this.Data, Path = new PropertyPath("CurrentContact.Login"), Mode = BindingMode.OneWay });

...然后我将看到该值。

基于这些症状,以及我的第一个示例有效但实际代码无效的事实,有人能想到我应该寻找罪魁祸首的任何地方吗?

1 个答案:

答案 0 :(得分:0)

U。弄清楚了。我那里有一段非常古老的代码,它更改了Window和Textbox之间的容器元素的DataContext,从而中断了正确的绑定。我以为我删除了所有内容,但没有删除。正如Erno de Weerd所建议的那样,它DID引发了错误,但是该错误在某些启动日志记录中丢失了。我们可以关闭这个。