[英]Approach for defining bindable properties for Xaml custom control wrappers for UWP/WinUI
I commonly find myself wanting to wrap one or multiple UserControl
s into a single one for reusability reasons.出于可重用性的原因,我经常发现自己想将一个或多个
UserControl
包装成一个。 In other frameworks/libraries this seems to be far more common/trivial to achieve.在其他框架/库中,这似乎更常见/更容易实现。 I take that in most frameworks utilizing Xaml, defining custom controls is not as common due to the MVVM approach, which might be the reason there is no useful documentation for this around There are a lot of vaguely similar questions on this topic, but I failed to find one that concisely elaborates on the ideal way to achieve this.
我认为在大多数使用 Xaml 的框架中,由于 MVVM 方法,定义自定义控件并不常见,这可能是没有有用的文档的原因 关于这个主题有很多模糊相似的问题,但我失败了找到一个简明扼要地阐述实现这一目标的理想方法的方法。
Background背景
This is how I would go about in in Blazor.这就是我在 Blazor 中的 go 的方式。 Defining a property with the
Parameter
property results in a one-way binding and updates the component when that passed parameter changes.使用
Parameter
属性定义属性会导致单向绑定,并在传递的参数更改时更新组件。
[Parameter]
public bool Value { get; set; }
If Two way binding is desired, one has to define a corresponding callback explicitly and configure two-way binding inside the parent with the @bind-
syntax.如果需要双向绑定,则必须显式定义相应的回调,并使用
@bind-
语法在父级内部配置双向绑定。
[Parameter]
public EventCallback<bool> ValueChanged { get; set; }
private async Task SetValue(bool value)
{
if (Value != value)
{
Value = value;
await ValueChanged.InvokeAsync(value);
}
}
In React this is quite similar though the parent has to explicitly pass an event callback as there is no true two-way binding.在 React 中,这非常相似,尽管父级必须显式传递事件回调,因为没有真正的双向绑定。
Issue问题
I can't get my head around how to do this in Xaml.我无法理解如何在 Xaml 中执行此操作。 I take that the usual way to define a property on a custom control is a registered
DependencyProperty
.我认为在自定义控件上定义属性的常用方法是注册的
DependencyProperty
。 My approach so far was:到目前为止,我的方法是:
DependencyProperty
;DependencyProperty
; Here is a sample of a slider that display's its discrete index next to it.这是 slider 的示例,它旁边显示其离散索引。
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Slider x:Name="IndexSlider"
Grid.Column="0"
TickFrequency="1"
Minimum="0"
Value="{x:Bind Value, Mode=TwoWay}"
Maximum="{x:Bind Maximum, Mode=OneWay}"
Foreground="Blue"/>
<TextBlock VerticalAlignment="Center"
HorizontalAlignment="Right"
Grid.Column="1"
Margin="6,0,0,0"
Text="{x:Bind local:WrappedSlider.DiscretePaginate(IndexSlider.Value, Maximum), Mode=OneWay}"/>
</Grid>
public sealed partial class WrappedSlider : UserControl
{
public static readonly DependencyProperty ValueProperty = (/*...*/);
public double Value
{
get { return (double)GetValue(ValueProperty); }
set
{
SetValue(ValueProperty, value);
}
}
public static readonly DependencyProperty MaximumProperty = (/*...*/);
public double Maximum
{
get { return (double)GetValue(MaximumProperty); }
set
{
SetValue(MaximumProperty, value);
}
}
public WrappedSlider()
{
InitializeComponent();
}
public static string DiscretePaginate(double currentIndex, double upperBound) => $"{currentIndex}/{upperBound}";
}
While this approach works for simple controls (in most cases so far) there is a plenty of things disturbing me.虽然这种方法适用于简单的控制(到目前为止在大多数情况下),但有很多事情让我感到不安。
My questions我的问题
DependencyProperty
an issue at all or does it yield any pitfalls? DependencyProperty
的包装器是一个问题,还是会产生任何陷阱? It appears to me as there is no single source of truth anymore, but the inner control's value as well as the DependencyProperty
's backing field.DependencyProperty
的支持字段。 Can someone who has no idea about my control's implementation be ensured that he can reliably two-way to my control (or one-way bind for read-only controls/when reverse binding is not needed).x:Bind
syntax the right approach here or should I give the inner control a x:Name
and set/get its value through the outer property's getter/setter? x:Bind
语法在这里是正确的方法还是应该给内部控件一个x:Name
并通过外部属性的 getter/setter 设置/获取它的值? I noticed children occasionally not updating when using {x:Bind Variable, Mode=OneWay}
and invoking the setter inside the code-behind, while doing MyControlsName.Value =
did.{x:Bind Variable, Mode=OneWay}
并在代码隐藏中调用 setter 时偶尔不会更新,同时执行MyControlsName.Value =
did。 Or should I even use a entirely different approach.INotifyPropertyChanged
be feasible here? INotifyPropertyChanged
在这里可行吗? This post lists various advantages, but it appears to me as something that's exclusively used for the ViewModel
in a MVVM architecture.ViewModel
的东西。 I really could use some input here.我真的可以在这里使用一些输入。 This seems like something that should be self-explanatory, but the countless ways to implement bindings in Xaml on top of the widely used MVVM approach makes this very obstructive for someone with a background in Blazor.
这似乎应该是不言自明的,但是在广泛使用的 MVVM 方法之上,在 Xaml 中实现绑定的无数方法使得这对于具有 Blazor 背景的人来说非常困难。
Can someone who has no idea about my control's implementation be ensured that he can reliably two-way to my control (or one-way bind for read-only controls/when reverse binding is not needed).
是否可以确保不了解我的控件实现的人可以可靠地双向绑定我的控件(或单向绑定只读控件/不需要反向绑定时)。
Yes, when you create data binding between property and control.是的,当您在属性和控件之间创建数据绑定时。 This is the bridge where they could connect with each other and receive changes from the other side.
这是他们可以相互连接并接收来自另一方的更改的桥梁。 It's reliable unless you manually change the value in code.
除非您手动更改代码中的值,否则它是可靠的。
Is the x:Bind syntax the right approach here or should I give the inner control ax:Name and set/get its value through the outer property's getter/setter?
x:Bind 语法在这里是正确的方法还是应该给内部控件 ax:Name 并通过外部属性的 getter/setter 设置/获取其值?
Using x:Bind or Binding syntax is the correct way to implement data binding.使用x:Bind或Binding语法是实现数据绑定的正确方法。
Might INotifyPropertyChanged be feasible here?
INotifyPropertyChanged 在这里可行吗?
INotifyPropertyChanged
interface is used for data-binding. INotifyPropertyChanged
接口用于数据绑定。 When you want to use two-way binding, you will need to implement this interface.当你想使用双向绑定时,你需要实现这个接口。 This is a data-binding implementation.
这是一个数据绑定实现。 Generally, MVVM mode uses data-binding, as a result,
INotifyPropertyChanged
interface is often used in MVVM mode. MVVM模式一般采用数据绑定,因此在MVVM模式下经常使用
INotifyPropertyChanged
接口。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.