【问题标题】:UWP Two-way binding in a control template控件模板中的 UWP 双向绑定
【发布时间】:2019-10-26 08:17:59
【问题描述】:

我有一个带有 Text 属性的自定义控件,它应该双向绑定到数据上下文的属性。
绑定只发生在开头(我猜是一次),但不响应任何文本更改。

我的自定义控件:

public sealed class MyTextControl : Control
{
    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
        "Text", typeof(string), typeof(MyTextControl), new PropertyMetadata(default(string)));

    public string Text
    {
        get => (string)GetValue(TextProperty);
        set => SetValue(TextProperty, value);
    }

    public MyTextControl()
    {
        DefaultStyleKey = typeof(MyTextControl);
    }
}

控制模板:

<Style TargetType="local:MyTextControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:MyTextControl">
                <Border
                    Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}">

                    <TextBox
                        BorderBrush="Black"
                        BorderThickness="1"
                        Text="{Binding Text, RelativeSource={RelativeSource TemplatedParent}}" />
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

我正在调用控件:

<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
    <myTextControl:MyTextControl
        Width="500"
        HorizontalAlignment="Center"
        VerticalAlignment="Center"
        Text="{x:Bind Greeting, Mode=TwoWay}" />

    <Button
        Margin="50"
        HorizontalAlignment="Center"
        VerticalAlignment="Center"
        Content="Submit" />
</StackPanel>

Greeting 是 DP 后面的代码设置为 Hello World!

我希望在问候语或文本更改文本中达到一个断点,但我没有。
似乎双向绑定效果不佳。 与 WPF 有什么不同?我怎样才能让它工作?

【问题讨论】:

  • naa 这不是问题。因为在 LostFocus (默认)上它也不起作用。只是为了练习,我已将此添加到模板中的 TextBox 中,但仍然没有达到断点。
  • 不,它不是重复的。绑定双向绑定不仅必须在控件本身上指定,还必须在控件模板内部指定。您指定的问题是一个简单的绑定场景,根本没有自定义控件
  • 问题还是一样。默认情况下没有双向绑定。
  • 同样的问题可能会以不同的方式出现。这不是在控件内绑定而是在控件模板内绑定的场景。争论这个事实很糟糕

标签: wpf uwp binding win-universal-app custom-controls


【解决方案1】:

快速解答

首先,a {TemplateBinding} is always a one-way binding

其次,从 Windows 10 版本 1809 开始,you can use the {x:Bind} markup extension anywhere you use {TemplateBinding} in a ControlTemplate

因此,您可以在ControlTemplate 中使用{x:Bind} 而不是{TemplateBinding},并具有双向绑定功能 (mode=TwoWay)。

额外帮助

话虽如此,在ControlTemplate 中使用{x:Bind} 并不像用{x:Bind} 替换{TemplateBinding} 的实例那么简单。它涉及一些其他的变化。考虑到 Visual Studio 会自动 (1) 创建一个名为 MyControl.cs 的类文件,并且 (2) 在 SomeProject\Themes\Generic.xaml 中使用 ControlTemplate 分配控件的样式(如果文件夹和资源文件不存在,则它们已创建),按照这些说明让您的控件使用 {x:Bind}

  1. 记住TargetType property is required (not optional) on ControlTemplate when using {x:Bind}

  2. 在文件夹Themes\ 中,创建一个名为Generic.xaml.cs 的新类文件,并声明一个名为Generic 的公共密封部分类,其公共构造函数只调用InitializeComponent

    // Themes\Generic.xaml.cs
    namespace SomeSolution.SomeProject.Themes
    {
        public sealed partial class Generic
        {
            public Generic() => InitializeComponent();
        }
    }
    

    (见注 A.)

  3. 将以下作为属性添加到Generic.xaml 的根标记:

    <!-- Themes\Generic.xaml -->
    <ResourceDictionary x:Class="SomeProject.Themes.Generic" ...>
        ...
    </ResourceDictionary>
    

    (见注 B.)

  4. Application.Resources(.MergedDictionaries) 中实例化包含控件样式的 ready-for-xBind 类型 (Generic) :

    <!-- App.xaml -->
    <Application ...>
        <Application.Resource>
            <Generic xmlns="using:Whatever.Namespace" />
        </Application.Resources>
        ...
    </Application>
    

    (见注释 C、D 和 E。)


注意事项

A. {x:Bind} markup extension generates source code at compile-time,所以需要初始化生成的代码]。

B. x:Class joins partial classes 在标记和代码隐藏之间]。

C. A resource dictionary with code-behind is reused by instantiating its type(以便调用 InitializeComponent)而不是引用其文件名。

D. Application.Resources can be reused everywhere。如果不打算这样做,可以在SomePage.ResourcesSomeFrameworkElement.Resources 等中实例化具有该样式的类。

E. Themes\Generic.xaml 中的资源不需要与 Application.Resources “合并”,以便它们在任何地方都可用。它们按约定提供。但是,由于此资源字典确实需要显式实例化,无需将文件命名为Generic.xamlGeneric.xaml.cs(在Themes/ 内)。文件(和类)可以​​命名不同,命名空间和位置也可以不同。 只要它们被相应地实例化,控件就会起作用

【讨论】:

  • 你好。当像这样在 Application.Resources 中声明 时,我收到一个错误,指出它在命名空间中找不到通用类型。我应该使用什么命名空间来正确检测类型?
【解决方案2】:

WPF 的小改动需要一些时间才能理解
我还需要更新模板以支持双向绑定

Text="{Binding Path=Text, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" />

我们曾经有过 FrameworkPropertyMetaData 但没有更多...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-06
    • 1970-01-01
    • 2011-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-09
    相关资源
    最近更新 更多