我最近用 Binding Mode = OneWayToSource
做了很多测试,但我仍然不知道为什么会发生某些事情。
例如,我在类构造函数中的 dependency property
上设置了一个值。现在,当 Binding 初始化时,Target
属性被设置为其默认值。意味着 dependency property
被设置为 null
并且我丢失了我在 constructor
中初始化的值。
为什么会这样? Binding Mode
没有按照名称描述的方式工作。它应该只更新 Source
而不是 Target
这是代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MyViewModel();
}
private void OnClick(object sender, RoutedEventArgs e)
{
this.DataContext = new MyViewModel();
}
}
这是 XAML:
<StackPanel>
<local:MyCustomControl Txt="{Binding Str, Mode=OneWayToSource}"/>
<Button Click="OnClick"/>
</StackPanel>
这是 MyCustomControl:
public class MyCustomControl : Control
{
public static readonly DependencyProperty TxtProperty =
DependencyProperty.Register("Txt", typeof(string), typeof(MyCustomControl), new UIPropertyMetadata(null));
static MyCustomControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl), new FrameworkPropertyMetadata(typeof(MyCustomControl)));
}
public MyCustomControl()
{
this.Txt = "123";
}
public string Txt
{
get { return (string)this.GetValue(TxtProperty); }
set { this.SetValue(TxtProperty, value); }
}
}
这是 View 模型:
public class MyViewModel : INotifyPropertyChanged
{
private string str;
public string Str
{
get { return this.str; }
set
{
if (this.str != value)
{
this.str = value; this.OnPropertyChanged("Str");
}
}
}
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null && propertyName != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
最佳答案
this.Txt = "123";
这是用本地值替换您的绑定(bind)。见 dependency property value precedence 。当您真的想要
DependencyObject.SetValue
时,您实际上是在调用 DependencyProperty.SetCurrentValue
。此外,您需要等到生命周期的后期才能执行此操作,否则 WPF 将更新 Str
两次:一次是“123”,然后是 null
:protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
this.SetCurrentValue(TxtProperty, "123");
}
如果您在用户控件的构造函数中执行此操作,它会在 WPF 实例化它时执行,但会在 WPF 加载和反序列化并应用您的 BAML 时立即替换。
更新:抱歉,我误解了你的确切问题,但现在有一个重现,复制在下面。我错过了您随后更新
DataContext
的部分。我通过在数据上下文更改时设置当前值来解决此问题,但在单独的消息中。否则,WPF 会忽略将更改转发到新数据源。using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace SO18779291
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.setNewContext.Click += (s, e) => this.DataContext = new MyViewModel();
this.DataContext = new MyViewModel();
}
}
public class MyCustomControl : Control
{
public static readonly DependencyProperty TxtProperty =
DependencyProperty.Register("Txt", typeof(string), typeof(MyCustomControl), new UIPropertyMetadata(OnTxtChanged));
static MyCustomControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl), new FrameworkPropertyMetadata(typeof(MyCustomControl)));
}
public MyCustomControl()
{
this.DataContextChanged += (s, e) =>
{
this.Dispatcher.BeginInvoke((Action)delegate
{
this.SetCurrentValue(TxtProperty, "123");
});
};
}
public string Txt
{
get { return (string)this.GetValue(TxtProperty); }
set { this.SetValue(TxtProperty, value); }
}
private static void OnTxtChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
Console.WriteLine("Changed: '{0}' -> '{1}'", e.OldValue, e.NewValue);
}
}
public class MyViewModel : INotifyPropertyChanged
{
private string str;
public string Str
{
get { return this.str; }
set
{
if (this.str != value)
{
this.str = value; this.OnPropertyChanged("Str");
}
}
}
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null && propertyName != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
XAML:
<Window x:Class="SO18779291.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SO18779291"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<local:MyCustomControl Txt="{Binding Str, Mode=OneWayToSource}"/>
<Button x:Name="setNewContext">New Context</Button>
<TextBlock Text="{Binding Str, Mode=OneWay}"/>
</StackPanel>
</Window>
关于c# - 绑定(bind) OneWayToSource - 奇怪的行为,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18779291/