c# – 具有绑定模式的WPF UserControl = OneWay
我正在尝试使用可绑定属性制作一个示例
WPF用户控件(可能更好地说“开发人员控件”).我的代码包含以下文件:
----- MainWindow.xaml ----- <Window x:Class="Test_Binding.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:testBinding="clr-namespace:Test_Binding" Title="MainWindow" Height="350" Width="525"> <StackPanel> <testBinding:MyLabelledTextBox x:Name="MLTB" LabelText="My custom control: MyLabelledTextBox" Text="{Binding StringData,Mode=OneWay}" /> </StackPanel> </Window> ----- MainWindow.xaml.cs ----- using System.Windows; namespace Test_Binding { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { this.DataContext = new MyDataObject(); this.InitializeComponent(); } } } ----- MyDataObject.cs ----- using System.Runtime.CompilerServices; // CallerMemberName using System.ComponentModel; // INotifyPropertyChanged namespace Test_Binding { public class MyDataObject : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private string stringData; public string StringData { get { return this.stringData; } set { if (value != this.stringData) { this.stringData = value; this.OnPropertyChanged(); } } } private void OnPropertyChanged([CallerMemberName] string propertyName = null) { if (this.PropertyChanged != null) { this.PropertyChanged(this,new PropertyChangedEventArgs(propertyName)); } } public MyDataObject() { System.Timers.Timer t = new System.Timers.Timer(); t.Interval = 10000; t.Elapsed += t_Elapsed; t.Start(); } private void t_Elapsed(object sender,System.Timers.ElapsedEventArgs e) { this.StringData = ((this.StringData ?? string.Empty).Length >= 4 ? string.Empty : this.StringData + "*"); } } } ----- MyLabelledTextBox.xaml ----- <UserControl x:Class="Test_Binding.MyLabelledTextBox" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"> <StackPanel Background="Yellow"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="0.5*" /> <ColumnDefinition Width="0.5*" /> </Grid.ColumnDefinitions> <Label x:Name="MLTBLabel" Grid.Row="0" Grid.Column="0" /> <TextBox x:Name="MLTBTextBox" Grid.Row="0" Grid.Column="1" Background="Yellow" Text="{Binding Text,Mode=TwoWay}" /> </Grid> </StackPanel> </UserControl> ----- MyLabelledTextBox.xaml.cs ----- using System.Windows; using System.Windows.Controls; namespace Test_Binding { /// <summary> /// Interaction logic for MyLabelledTextBox.xaml /// </summary> public partial class MyLabelledTextBox : UserControl { public static readonly DependencyProperty LabelTextProperty = DependencyProperty.Register("LabelText",typeof(string),typeof(MyLabelledTextBox),new PropertyMetadata(string.Empty,MyLabelledTextBox.LabelTextPropertyChanged)); public string LabelText { get { return (string)this.GetValue(MyLabelledTextBox.LabelTextProperty); } set { this.SetValue(MyLabelledTextBox.LabelTextProperty,value); } } public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text",MyLabelledTextBox.TextPropertyChanged)); public string Text { get { return (string)this.GetValue(MyLabelledTextBox.TextProperty); } set { this.SetValue(MyLabelledTextBox.TextProperty,value); } } public MyLabelledTextBox() { this.InitializeComponent(); this.MLTBLabel.DataContext = this; this.MLTBTextBox.DataContext = this; this.MLTBTextBox.TextChanged += new TextChangedEventHandler(this.MLTBTextBox_TextChanged); } private void MLTBTextBox_TextChanged(object sender,TextChangedEventArgs e) { this.Text = this.MLTBTextBox.Text; // transfer changes from TextBox to bindable property (bindable property change notification will be fired) } private static void LabelTextPropertyChanged(DependencyObject d,DependencyPropertyChangedEventArgs e) { ((MyLabelledTextBox)d).MLTBLabel.Content = (string)e.NewValue; // transfer changes from bindable property to Label } private static void TextPropertyChanged(DependencyObject d,DependencyPropertyChangedEventArgs e) { ((MyLabelledTextBox)d).MLTBTextBox.Text = (string)e.NewValue; // transfer changes from bindable property to TextBox } } } 有一个“MyDataObject”类的实例,其属性为“StringData”,使用计时器定期修改.我的用户控件绑定到其属性“StringData”.如果“MainWindow.xaml”文件中的绑定设置为“TwoWay”,则用户控件会不断更新,但如果我使用“OneWay”绑定,则用户控件会更新一次,然后“PropertyChanged” “MyDataObject”类实例的事件不会再次触发,因为它突然没有订阅者. 为什么“OneWay”绑定在被调用一次后停止工作? 解决方法
首先.
this.MLTBLabel.DataContext = this; this.MLTBTextBox.DataContext = this; Noooooooooooooooo! 决不.永远.永远.从代码隐藏中设置DataContext.一旦执行此操作,您就会失去从父控件绑定到用户控件的依赖项属性的神奇美感.换句话说,就是不要这样做. 这是你应该做的: 为UserControl提供x:名称. <UserControl ... x:Name="usr"> 将UserControl的依赖属性绑定到元素,如下所示: <TextBlock Text="{Binding MyDependencyProperty,ElementName=usr}" ... /> 将UserControl的DataContext属性绑定到元素,如下所示: <TextBlock Text="{Binding MyDataContextProperty}"/> 使用此方法将允许您在MainWindow中设置UserControl的DataContext,但仍然能够绑定到UserControl中UserControl的依赖项属性.如果在代码隐藏中设置UserControl的DataContext,则无法绑定到依赖项属性. 现在,解决你的实际问题. 所有这些: private void MLTBTextBox_TextChanged(object sender,TextChangedEventArgs e) { this.Text = this.MLTBTextBox.Text; // transfer changes from TextBox to bindable property (bindable property change notification will be fired) } private static void LabelTextPropertyChanged(DependencyObject d,DependencyPropertyChangedEventArgs e) { ((MyLabelledTextBox)d).MLTBLabel.Content = (string)e.NewValue; // transfer changes from bindable property to Label } private static void TextPropertyChanged(DependencyObject d,DependencyPropertyChangedEventArgs e) { ((MyLabelledTextBox)d).MLTBTextBox.Text = (string)e.NewValue; // transfer changes from bindable property to TextBox } 忘掉它.看起来你正试图解决我之前谈到的错误行为. 您应该绑定到您的依赖项属性: <Label Grid.Row="0" Grid.Column="0" Text="{Binding Text,ElementName=usr}"/> 您遇到的另一个问题是,在您的MainWindow中,您正在使用UserControl上的绑定. Text="{Binding StringData,Mode=OneWay}" 现在,因为您已经在代码隐藏中设置了DataContext.这有效地说的是: 从当前控件的DataContext绑定到StringData. 在您的情况下,与您的MainWindow DataContext完全不同. (因为您在UserControl中明确设置了DataContext). 贯穿我之前提到的.有很多东西需要学习,但这是一个开始. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |