首页 > 解决方案 > 我应该在 WPF 中使用自定义控件声明绑定选项的页面

问题描述

我是在 wpf 中进行自定义控件的新手。
我完全不了解自定义控件的绑定技术。
让我给你看看我的练习。

我在cs文件中声明了我的自定义控件

public class CustomControl1 : Control
{
    static CustomControl1()
    {
        DefaultStyleKeyProperty.OverrideMetadata
            (typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1))
            );
    }

    // Using a DependencyProperty as the backing store for Text.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TextaaProperty =
        DependencyProperty.Register(
            "Textaa", 
            typeof(string), typeof(CustomControl1),
            new PropertyMetadata(null));

    public string Textaa
    {
        get { return (string)GetValue(TextaaProperty); }
        set { SetValue(TextaaProperty, value); }
    }
 }

在 Generic.xaml 中,我在 Generic.xaml 中为我的自定义控件声明了模板样式。

<Style TargetType="{x:Type local:CustomControl1}">
    <Setter Property="Background" Value="DimGray"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:CustomControl1}">
                <TextBox Background="{TemplateBinding Background}" 
                           Text="{Binding Textaa, 
                                 RelativeSource={RelativeSource TemplatedParent}}">
                </TextBox>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

为了给我的控件发文本,我为只有 name 属性并且只是从 INPC 继承的 Data 对象创建了 My Custom 类

    public MainWindow()
    {
        InitializeComponent();
        DataContext = new DataObject() { name = "Jeong Yo Han" };
    }

    public class DataObject : INotifyPropertyChanged
    {
        private string _name;
        public string name
        {
            get { return _name; }
            set {
                _name = value;
                onPropertyChanged("name");
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        public void onPropertyChanged(string name)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }  

在我的主窗口页面中,我声明了我的自定义控件标签

<Grid>
    <cc:CustomControl1 Background="Red" 
                       Textaa="{Binding name ,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
    </cc:CustomControl1>
</Grid>

我试图测试模板样式中的 templatedParent 是否适用于双向绑定。(请参阅 RelativeSource= { Rela ... TemplatedParent } )。

然后我运行我的程序来查看何时在 DataObject 类中获得命中名称设置器属性。即使我添加了 UpdateSourceTrigger=PropertyChanged,但是当我更改 TextBox 中的文本时它也不能正常工作。当我失去注意力时它会起作用,即使我输入了 UpdateSourceTrigger=PropertyChanged。

所以我改变了我的来源,就像下面的来源一样。

<!-- in Generic.xaml (Template style) -->
<TextBox Background="{TemplateBinding Background}" 
                           Text="{Binding Textaa, 
                           UpdateSourceTrigger=PropertyChanged,
                                 RelativeSource={RelativeSource TemplatedParent}}">
</TextBox>
<!--- in MainWindow.xaml--->
<cc:CustomControl1 Background="Red" 
                       Textaa="{Binding name ,Mode=TwoWay}" >
 </cc:CustomControl1>

正如我所料,这很好用。
并且以下不起作用,不是我预期的。

<!-- in Generic.xaml (Template style) -->
<TextBox Background="{TemplateBinding Background}" 
                           Text="{Binding Textaa, 
                           UpdateSourceTrigger=PropertyChanged, Mode=TwoWay,
                                 RelativeSource={RelativeSource TemplatedParent}}">
</TextBox>
<!--- in MainWindow.xaml--->
<cc:CustomControl1 Background="Red" 
                       Textaa="{Binding name}" >
 </cc:CustomControl1>

但是我很困惑,为什么我应该将 UpdateSourceTrigger 选项放在 StyleTemplate 和 Mode= TwoWayBinding 选项直接放在 customcontrol 标记的 Textaa 依赖属性中。

我需要一个解释。感谢您的阅读。

为了帮助您理解,我在下面添加了我的源代码。

单击此处查看完整来源

标签: c#wpfxamluwp

解决方案


更新 TextBox 的 Text 属性的 Binding 的源属性的默认行为是LostFocus

请参阅TextBox.Text 属性页上的备注:

在数据绑定方案中使用时,此属性使用 UpdateSourceTrigger.LostFocus 的默认更新行为。

但是,您不需要设置Mode=TwoWay,因为这已经是默认设置。所以 TextBox 声明应该是这样的:

<TextBox Background="{TemplateBinding Background}" 
         Text="{Binding Textaa,
                UpdateSourceTrigger=PropertyChanged,
                RelativeSource={RelativeSource TemplatedParent}}" />

不必在属性UpdateSourceTrigger=PropertyChanged的 Binding 上进行设置Textaa,因为(与 相比TextBlock.Text),您的自定义依赖属性的默认行为已经是PropertyChanged.

您还可以以默认情况下使其双向绑定的方式注册您的属性,这样您就不必Mode=TwoWayTextaaBinding 上进行设置:

public static readonly DependencyProperty TextaaProperty =
    DependencyProperty.Register(
        nameof(Textaa), typeof(string), typeof(CustomControl1),
        new FrameworkPropertyMetadata(
            null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

现在您可以像这样绑定Textaa属性:

<cc:CustomControl1 Textaa="{Binding name}" />

推荐阅读