2013-04-29 24 views
2

我正在使用OneWayToSource绑定,它似乎总是将我的源属性设置为null。为什么?这是我的麻烦,因为我需要源属性中的目标属性的值,而不是null。OneWayToSource窘境

这里是我的代码:

MyViewModel.cs:

public class MyViewModel 
{ 
    private string str; 

    public string Txt 
    { 
     get { return this.str; } 
     set { this.str = value; } 
    } 
} 

MainWindow.cs:

public MainWindow() 
{ 
    InitializeComponent(); 
    MyViewModel vm = new MyViewModel(); 
    vm.Txt = "123"; 
    this.DataContext = vm; 
} 

MainWindow.xaml:

<Window x:Class="OneWayToSourceTest.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525" 
     xmlns:local="clr-namespace:OneWayToSourceTest"> 
     <Grid> 
     <local:MyButton Content="{Binding Path=Txt, Mode=OneWayToSource}"/> 
     </Grid> 
</Window> 

MyButton.cs:

public class MyButton : Button 
{ 
    public MyButton() 
    { 
     this.Content = "765"; 
    } 
} 

target属性是MyButton.Content。源属性是MyViewModel.TxtTxt属性应该设置为“765”,但它是空的。

为什么我会收到空​​值而不是765?

编辑:

请看看里面MyButton构造。其实如果你会使用简单的TwoWay它会起作用。我测试了它,它与构造函数中设置的内容无关。它的东西与OneWayToSource绑定我猜。

我们解释我是如何用TwoWay绑定,我没有通过调用setvalue方法,但再包装或更好的内部设置构造函数中的DP值表示getter和setter我没有提供任何二传手因此为什么我做了我的TwoWay有点像它的OneWayToSource。我做了它来测试它的构造函数是否有错。我认为viewmodel内的属性值为765,所以这就是我的意思是TwoWay绑定。我只是测试它是否是控件构造函数。它的一切都很好,在构造函数中设置一个值。

通过隐藏二传手我的意思是 集合{}

+0

您是否收到任何BindingErrors? – Jehof 2013-04-29 13:33:18

+0

不,我不。 : - (( – 2013-04-29 13:33:54

回答

4

myButton的被通过的InitializeComponent DataContext的实例之前设置的,所以结合是没有生效时,它的构造器运行。尝试设置一个值点击按钮。

+0

我不能强制用户点击一个按钮来设置数值:) – 2013-04-29 14:31:05

+1

可能不是,但我已经向你解释为什么它不能正常工作,非常感谢你的支持!! – johndsamuels 2013-04-29 14:34:46

+0

When datacontext没有设置,Txt的值应该是123.请再次查看我的代码,一旦设置了DataContext,绑定应该将Txt的值更新为765.虽然问题是一旦绑定更新了值,值我很抱歉,但不管是在InitializeComponent之前还是之后,它仍然不能与OneWayToSource一起工作。请再次看看我的问题。我编辑它 – 2013-04-29 14:38:34

1

其实如果你会使用简单的双向它会工作。

我不能复制这个。根据您提供的代码,如果您使用TwoWay绑定模式,则视图模型Txt属性将等于“123”,它是在您的MainWindows构造函数中给出的值。

我测试了它和它无关的内容设定内部构造

雷切尔已经指出的那样,XAML绑定清除本地值。在之后发生绑定您的按钮构造函数代码被运行。绑定然后从依赖项属性的元数据中检索它的默认值。通过在绑定建立后(例如在Loaded事件中)在更合适的时间设置该值,可以很容易地解决这个问题。

这个简单的修改将提供所要的结果:

public class MyButton : Button 
{ 
    public MyButton() 
    { 
     this.Loaded += MyButton_Loaded; 
    } 

    void MyButton_Loaded(object sender, RoutedEventArgs e) 
    { 
     this.Content = "765"; 
    } 
} 

Rachels回答还提供了制备这种工作(重写属性默认元数据)的替代方法。

为什么每次有人使用OneWayToSource绑定后将initalizatin设置为 ?它对我没有意义。

我认为这对你没有意义的原因是因为你的TwoWay绑定测试不符合你的想法。

使用OneWayToSource结合:

使用OneWayToSource结合下面发生的事情:

  1. 你在它的构造函数设置MyButton.Content为 “123”。
  2. 您正在设置您的XAML中的OneWayToSource绑定。这清除您设定的值。
  3. 该绑定从属性元数据中检索默认属性值(null),并将ViewModel.Txt属性设置为等于此值。

如果您在按钮加载的事件中设置了MyButton.Content属性,则发生上述事件后,您的属性将设置为您希望的值。

您可以通过在MyViewModel.Txt属性获取器中放置断点来验证这一点。该值将按顺序设置为“123”,null和“756”。

使用双向绑定:

现在,如果你要改变你的XAML使用TwoWay结合会发生以下情况:

  1. 你在它的构造函数设置MyButton.Content为“123”。
  2. 您正在XAML中设置TwoWay绑定。这清除您设定的值。
  3. 你的控制值(MyButton.Content)使用在这种情况下是你的ViewModels Txt属性导致在MyButton.Content属性等于“123”更新。
+0

我不是一个不知道为什么只是使用事物的粉丝。在这种情况下,我只需要相信你们。至于我已经说过我的自定义双向绑定的例子,我成功地证明了它不是构造函数。然而,让我们接受这个答案。谢谢 – 2013-04-29 19:01:27

8

Content属性只能设置为一个值,你是更换值“756”具有约束力。

正如我在my answer到您的其他问题向你指出,WPF运行顺序代码:

  • 正常 - 构造函数这里
  • 的DataBind
  • 运行渲染
  • 加载

因此,首先完成的是您的MainWindow构造函数运行。这将创建按钮,该按钮调用Button的构造函数,并将Button.Content设置为“765”。

但是,在XAML中为Button指定了不同的Content属性 - 一个绑定。因此,您的按钮对象被创建,Content属性被设置为“765”,然后Content属性被设置为{Binding Path=Txt, Mode=OneWayToSource}

这是一样的做这样的事情:

var b = new MyButton(); 
b.Content = "756"; 
b.Content = new Binding(...); 

您是更换Content财产。

(和技术,最后一行应b.SetBinding(MyButton.ContentProperty, new Binding(...));的值正确绑定,但是我用的是更基本的语法,使之更容易理解这个问题。)

循环中的下一个步骤是数据绑定,因此对Content属性的绑定进行评估。

既然是OneWayToSource绑定,属性只更新后,能够改变的源元素,因为这是第一次结合正在评估,将其设置为任何默认是这个DependencyProperty,使他们的源'重新同步。

Button.Content依赖项属性的情况下,默认值是null,所以你的源元素被设置为null

因为DP从绑定中获取值而不是使用默认值,所以您看不到此行为与TwoWay绑定。

如果你要设置你的价值的结合已经成立后,如在Loaded事件的按钮,你会看到你的源属性正确地得到更新当您设置按钮的Content

void MyButton_Loaded(object sender, EventArgs e) 
{ 
    ((Button)sender).Content = "756"; 
} 

末后的,如果你想从您的自定义控制设置Content属性的默认值,则需要覆盖MetaData该属性,像这样:

// Note that this is the static constructor, not the normal one 
static MyButton() 
{ 
    ContentProperty.OverrideMetadata(typeof(MyButton), 
     new FrameworkPropertyMetadata("756")); 
} 

这将使得Content属性的默认值为"756"而不是null

+0

+1我删除了我的答案,因为它更好,因为它解释了为什么绑定按照它的方式工作。我也不知道你可以设置一个像这样的绑定'b.Content = new Binding(...)',并且认为你必须使用'SetBinding(..)'方法。谢谢你的提示。 – 2013-04-29 19:27:58

+0

@Benjamin Errmmm可能是一个错误:)我认为设置'b.Content = new Binding(...)'将设置Content属性为绑定对象,而不是评估它(必须测试是当然)。我刚刚使用了这种语法,因为它可以让你更容易理解发生的事情:) – Rachel 2013-04-29 19:42:17

+0

是的,你是对的:)当我测试这个时,我认为我有它的工作,但我错了(我的测试是有缺陷的)。 – 2013-04-29 19:57:08