我正在使用OneWayToSource
绑定,似乎它始终将我的source属性设置为null。为什么会这样?它给我带来了麻烦,因为我需要来自source属性中的target属性的值而不是null。
这是我的代码:
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";
}
}
目标属性为MyButton.Content
。源属性为MyViewModel.Txt
。 Txt
属性应设置为“765”,但它应为null。
为什么我会收到null而不是765?
修改
请查看MyButton
构造函数。实际上如果您使用简单的TwoWay
它将起作用。我测试了它,它与构造函数中设置的内容无关。它的结果我猜是OneWayToSource
。
现在解释我是如何使用TwoWay
绑定的,我确实通过调用setvalue
方法在构造函数中设置了dp的值,但是然后在包装器中或更好地说getter和setter我没有提供任何setter因此为什么我使TwoWay
看起来像OneWayToSource
。我做了它来测试它的构造函数是否有错。我认为viewmodel中的属性值为765,这就是我对TwoWay
绑定的意思。我刚测试它是否是控件构造函数。在构造函数中设置一个值就可以了。
通过隐藏setter我的意思是这个 设置{}
答案 0 :(得分:8)
Content
属性只能设置为单个值,并且用绑定替换值“756”。
正如我在my answer中向您指出的另一个问题,WPF按此顺序运行代码:
所以首先要做的就是运行MainWindow
构造函数。这将创建调用Button的构造函数的按钮,并将Button.Content
设置为“765”。
但是在Button
的XAML中,您指定了不同的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
。
您没有看到TwoWay
绑定的这种行为,因为DP从绑定中获取它的值而不是使用默认值。
如果您在设置绑定后设置了值,例如在按钮的Loaded
事件中,则在设置Button的{{1}时,您会看到源属性正确更新}}
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"
答案 1 :(得分:4)
MyButton在设置DataContext之前由InitializeComponent实例化,因此绑定在其构造运行时不会生效。尝试单击按钮设置一个值。
答案 2 :(得分:1)
实际上如果您使用简单的TwoWay它将起作用。
我不能复制这个。给定您提供的代码,如果使用TwoWay
绑定模式,则viewmodels Txt
属性将等于“123”,它是在MainWindows
构造函数中给出的值。
我测试了它,它与在构造函数
中设置的内容无关
正如Rachel所指出的,XAML Binding清除了本地值。 运行按钮构造函数代码后,发生绑定。然后,绑定从依赖项属性的元数据中检索它的默认值。在建立绑定后,例如在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
绑定会发生以下情况:
MyButton.Content
设置为“123”。OneWayToSource
绑定。这清除了您设置的值。ViewModel.Txt
属性设置为等于此值。如果在按钮加载事件中设置MyButton.Content
属性,则在上述事件发生之后,将属性设置为您希望的值。
您可以通过在MyViewModel.Txt
属性获取器中放置断点来自行验证。该值将按此顺序设置为“123”,null和“756”。 / p>
使用TwoWay绑定:
现在,如果您要更改XAML以使用TwoWay
绑定,则会发生以下情况:
MyButton.Content
设置为“123”。TwoWay
绑定。这清除了您设置的值。MyButton.Content
)使用来源进行更新,在这种情况下,您的viewModels Txt
属性会导致您的MyButton.Content
属性等于“123”。