Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-cloud-platform/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 绑定模式为单向的WPF UserControl_C#_Wpf_Xaml_Binding_User Controls - Fatal编程技术网

C# 绑定模式为单向的WPF UserControl

C# 绑定模式为单向的WPF UserControl,c#,wpf,xaml,binding,user-controls,C#,Wpf,Xaml,Binding,User Controls,我正在尝试制作一个具有可绑定属性的示例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

我正在尝试制作一个具有可绑定属性的示例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", typeof(string), typeof(MyLabelledTextBox),
            new PropertyMetadata(string.Empty, 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
        }
    }
}
----MainWindow.xaml-----
-----MainWindow.xaml.cs-----
使用System.Windows;
命名空间测试绑定
{
/// 
///MainWindow.xaml的交互逻辑
/// 
公共部分类主窗口:窗口
{
公共主窗口()
{
this.DataContext=新的MyDataObject();
this.InitializeComponent();
}
}
}
-----MyDataObject.cs-----
使用System.Runtime.CompilerServices;//CallerMemberName
使用System.ComponentModel;//InotifyProperty已更改
命名空间测试绑定
{
公共类MyDataObject:INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
私有字符串数据;
公共字符串字符串数据
{
获取{返回this.stringData;}
设置
{
if(值!=this.stringData)
{
this.stringData=值;
this.OnPropertyChanged();
}
}
}
私有void OnPropertyChanged([CallerMemberName]字符串propertyName=null)
{
if(this.PropertyChanged!=null)
{
this.PropertyChanged(this,newpropertychangedventargs(propertyName));
}
}
公共MyDataObject()
{
System.Timers.Timer t=新的System.Timers.Timer();
t、 间隔=10000;
t、 已用时间+=t_已用时间;
t、 Start();
}
私有无效时间(对象发送方,System.Timers.ElapsedEventArgs e)
{
this.StringData=((this.StringData??string.Empty).Length>=4?string.Empty:this.StringData+“*”);
}
}
}
-----MyLabelledTextBox.xaml-----
-----MyLabelledTextBox.xaml.cs-----
使用System.Windows;
使用System.Windows.Controls;
命名空间测试绑定
{
/// 
///MyLabelledTextBox.xaml的交互逻辑
/// 
公共部分类MyLabelledTextBox:UserControl
{
公共静态只读DependencyProperty LabelTextProperty=
DependencyProperty.Register(“LabelText”、typeof(字符串)、typeof(MyLabelledTextBox),
新的PropertyMetadata(string.Empty,MyLabelledTextBox.LabelTextPropertyChanged));
公共字符串标签文本
{
获取{返回(字符串)this.GetValue(MyLabelledTextBox.LabelTextProperty);}
set{this.SetValue(MyLabelledTextBox.LabelTextProperty,value);}
}
公共静态只读DependencyProperty TextProperty=
DependencyProperty.Register(“文本”、typeof(字符串)、typeof(MyLabelledTextBox),
新的PropertyMetadata(string.Empty,MyLabelledTextBox.TextPropertyChanged));
公共字符串文本
{
获取{返回(字符串)this.GetValue(MyLabelledTextBox.TextProperty);}
set{this.SetValue(MyLabelledTextBox.TextProperty,value);}
}
公共MyLabelledTextBox()
{
this.InitializeComponent();
this.MLTBLabel.DataContext=this;
this.MLTBTextBox.DataContext=this;
this.MLTBTextBox.TextChanged+=新的TextChangedEventHandler(this.MLTBTextBox\u TextChanged);
}
私有void MLTBTextBox_TextChanged(对象发送者,textchangedventargs e)
{
this.Text=this.MLTBTextBox.Text;//将更改从TextBox传输到可绑定属性(将触发可绑定属性更改通知)
}
私有静态void LabelTextPropertyChanged(DependencyObject d,DependencyPropertyChangedEventArgs e)
{
((MyLabelledTextBox)d).MLTBLabel.Content=(string)e.NewValue;//将更改从可绑定属性传输到标签
}
私有静态void TextPropertyChanged(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
((MyLabelledTextBox)d).MLTBTextBox.Text=(string)e.NewValue;//将更改从bindable属性传输到TextBox
}
}
}
有一个属性为“StringData”的“MyDataObject”类的实例,它使用计时器定期修改。我的用户控件绑定到其属性“StringData”。如果“MainWindow.xaml”文件中的绑定设置为“双向”,则用户控件将不断更新,但如果我使用“单向”绑定,则用户控件将更新一次,然后“MyDataObject”类实例的“PropertyChanged”事件不会再次触发,因为它突然没有订户

为什么“单向”绑定在被调用一次后会停止工作?
什么样的代码更改将允许“双向”和“单向”绑定继续工作?

在我看来,它是这样的:

this.StringData = ((this.StringData ?? string.Empty).Length >= 4 ? string.Empty : this.StringData + "*");
    }
计时器第一次启动时,
this.StringData
为空,因此表达式中的“?”返回
string.Empty
。然后检查长度是否大于等于4。它不是,因此它将
this.StringData
从null设置为
string.Empty
。由于属性仅在更改时更新,因此
INotifyPropertyChanged
触发一次

第二次,我们从
string.Empy
转到
string.Empty
,因此
INotifyPropertyChanged
不会触发,因为没有任何更改

基本上,计时器正在启动,但
this.StringData
现在卡在
string.Empty
上,这意味着
INotifyPropertyChanged
会忽略它。这是有道理的——如果属性没有实际更改,为什么WPF运行时要麻烦地将更新从C#属性推送到GUI?这只会让事情变慢
this.MLTBLabel.DataContext = this;
this.MLTBTextBox.DataContext = this;
<UserControl ...
    x:Name="usr">
<TextBlock Text="{Binding MyDependencyProperty, ElementName=usr}" ... />
<TextBlock Text="{Binding MyDataContextProperty}"/>
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}"/>
Text="{Binding StringData, Mode=OneWay}"