当我在按钮单击处理程序中设置数据上下文时,为什么数据绑定不起作用?

时间:2015-10-16 15:28:04

标签: c# .net wpf xaml data-binding

编辑:自从我第一次写完以来,我已经简化了这个问题。请参阅底部的代码示例。我明天会把帖子打扫干净。

我想在用户填写表单后设置DataContext,因为那时我知道需要创建的对象类型(基于用户选择的内容)。这样做的问题是BindingGroup.IsDirty标志是错误的,因为所有编辑都是由这一点完成的,我想这就是我对BindingGroup.UpdateSources的调用没有效果的原因。

基本上这就是我正在做的事情:

  1. 让用户填写表格。 DataContext尚未设置,但绑定已到位。
  2. buttonSave_Click处理程序中,创建并设置正确的DataContext对象(基于提供的用户输入),然后调用BindingGroup.UpdateSources并关闭对话框。
  3. 我意识到还有其他方法可以解决这个问题。可能甚至更好,但我真的只是试验DataBinding并试图更好地学习它。这就是为什么我要用这个来尝试很多可能的设计。

    最终,我可能会选择一个设计,我会问我需要回答的问题,以便了解为数据上下文创建的对象然后设置它并让它们从那里填写表单的其余部分。但是现在我想让它以另一种方式工作(如果它甚至可能)只是为了学习目的。

    编辑1:

    我已确定IsDirty标志不一定是我的问题,因为在设置DataContext之前,IsDirtytrue。然后在DataContext设置后立即变为false,所以我认为它会自动更新源,但是,我没有看到更改反映在我的数据对象中,因此显然由于某种原因失败了。

    我知道我的Bindings是正确的,因为如果我在Windows ctor中设置DataContext它会更新数据。将这两行代码移动到buttonSave_Click处理程序,它不再更新数据。

    我觉得有一些我想念的东西,当我想出来的时候,我会觉得我觉得很愚蠢:\

      

    更新1:

    我已确定BindingExpression.Worker.CanUpdate为false。通过查看BindingExpression的源代码,我可以看到它会导致它失败。现在弄清楚为什么这是错误的....

      

    更新2:

    随着我一直在做的所有阅读,我开始怀疑时间问题。 read this 我回家后能够尝试一下

      

    更新3:

    仍然在努力。这是一些代码。我已经简化了以获得最少的代码。

    这是数据对象。

    public abstract class Dog
        {
            public Dog(SexType sex)
            {
                NickName = string.Empty;
            }
    
            public string NickName { get; set; }
        }
    
     public class Stud : Dog
        {
            public Stud()
                : base(SexType.Male)
            {
            }
        }
    

    此代码有效:

    //code behind
    public partial class AddDogWindow : Window
    {
        public Dog NewDog { get; set; }
        public AddDogWindow()
        {
            InitializeComponent();
            //set the DataContext here and the data object will be updated as expected...
            NewDog = new Stud();
            DataContext = NewDog;
        }
    
        private void buttonSave_Click(object sender, RoutedEventArgs e)
        {
            DialogResult = true;
        }
    }
    

    和XAML

    <Window x:Class="PuppyMan.AddDogWindow"
            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:PuppyMan"
            mc:Ignorable="d"
            Title="AddStudDogWindow" Height="300" Width="300">
        <StackPanel>
            <TextBox HorizontalAlignment="Stretch" Text="{Binding NickName, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"></TextBox>
            <Button x:Name="buttonSave" Click="buttonSave_Click">Save</Button>
        </StackPanel>
    </Window>
    

    这是BREAKS的代码。

      public partial class AddDogWindow : Window
        {
            public Dog NewDog { get; set; }
            public AddDogWindow()
            {
                InitializeComponent();
            }
    
            private void buttonSave_Click(object sender, RoutedEventArgs e)
            {
                //Notice all I have changed is moving the set DataContext out of the ctor and into this handler. 
                //Now the data object no longer gets updated. 
                NewDog = new Stud();
                DataContext = NewDog;
                DialogResult = true;
            }
        }
    

    我的想法是让他们完全填写狗信息然后我只根据狗是男性还是女性的最终决定创建梭哈或者狗的对象。我想是一种懒惰的数据绑定。我知道这不是这种情况的最佳设计,但我想学习如何以学习方式这样做。或者了解为什么这个方法不起作用,或者很好,我只是想学习这个数据绑定的东西而且好!

      

    最终更新

    This post似乎与我的问题基本相同。我正在使用OneWayToSource,它总是将我的NickName属性设置为默认值(在本例中为“”)。问题不在于在设置器之后调用NickName getter,而是将其设置为“”。 UI保持原始值,直到我再次键入TextBox并且INotifyPropertyChange触发,然后所有内容再次同步。

    对我来说,似乎很像一个错误,OneWayToSource将推送“”而不是目标的当前值。但我很可能会错过理解。

2 个答案:

答案 0 :(得分:1)

设计您的表单,以便事先知道您将获得哪个对象。 这可以通过检查用户是否填充特定字段,或者他是否在表单中选择某个组合框值来完成。在适当的控件中,您可以设置datacontext。顺便说一句,Triggers最适合这里。为object-deciding-form-field设置触发器。如果你发布更多内容,或者在dropbox.com上传一些源代码,可以做更多的事情。

//////////

您已预先设置了Bindings,然后您正在更改DataContext。更改DataContext不会使TextBox值达到NickName属性。

其次,您已将UpdateSourceTrigger设置为PropertyChanged。因此,在更改DataContext后,您必须更改此属性。

这样做的一种方法是:

DataContext = NewDog;

/* this will trigger property changed */
txtDogNickName.Text = txtDogNickName.Text;

string newNickName = NewDog.NickName; // updated value appear here 

但这不是正确的做法。分别更改DataContext,然后编辑表单中的值。更改将正确传播。不要在同一个处理程序中做所有事情例如,您可以在一些Button1的单击处理程序中显示此表单并设置DataContext,然后使用另一个Button2的单击处理程序来获取表单值。

答案 1 :(得分:0)

我的问题与this post的问题相同。我正在使用OneWayToSource,当我更改DataContext时,我的属性被设置为一个默认值,它当前是“”而不是我期望的目标值。我找不到任何解决方法。我将设计这样,以便我知道要提前创建的对象,以便在构造函数中设置DataContext。