加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 具有绑定模式的WPF UserControl = OneWay

发布时间:2020-12-15 22:14:55 所属栏目:百科 来源:网络整理
导读:我正在尝试使用可绑定属性制作一个示例 WPF用户控件(可能更好地说“开发人员控件”).我的代码包含以下文件: ----- MainWindow.xaml -----Window x:Class="Test_Binding.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xml
我正在尝试使用可绑定属性制作一个示例 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”绑定在被调用一次后停止工作?
什么代码更改将允许“TwoWay”和“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).

贯穿我之前提到的.有很多东西需要学习,但这是一个开始.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读