自定义Xamarin.Forms控件中的绑定问题 [英] Binding issue in custom Xamarin.Forms control
问题描述
我对自定义控件上的绑定有一个奇怪的问题.我创建了一个自定义工具栏:
I have a strange problem with bindings on a custom control. I created a custom toolbar:
public partial class TopToolbar
{
public static readonly BindableProperty BackCommandProperty =
BindableProperty.Create(nameof(BackCommand), typeof(ICommand), typeof(TopToolbar), propertyChanged: BackCommandChanged);
public ICommand BackCommand
{
get => (ICommand) GetValue(BackCommandProperty);
set => SetValue(BackCommandProperty, value);
}
public TopToolbar()
{
InitializeComponent();
}
// for debug purposes only
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
Debug.WriteLine(BindingContext);
}
// for debug purposes only
private static void BackCommandChanged(BindableObject bindable, object oldvalue, object newvalue)
{
Debug.WriteLine($"old: {oldvalue}, new: {newvalue}");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Core.Controls.TopToolbar"
x:Name="TopToolbarView"
BindingContext="{x:Reference TopToolbarView}"
Orientation="Vertical">
<StackLayout Orientation="Horizontal"
HorizontalOptions="FillAndExpand"
<Image Source="{StaticResource Image.Toolbar.LeftArrow}">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding BackCommand}" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
</StackLayout>
我以这种方式在页面上使用它:
I use it on a page in this way:
<pages:ContentPage.Content>
<StackLayout BackgroundColor="{StaticResource LightGrayColor}"
Spacing="0"
Padding="0">
<controls:TopToolbar Title="Master Data" BackCommand="{Binding MyBackCommand}" />
页面的
BindingContext
是视图模型:
BindingContext
of the page is a view model:
public class MyCustomersPageModel
{
public RelayCommand MyBackCommand { get; set; }
public MyCustomersPageModel()
{
MyBackCommand = // command creation;
}
}
通过调试,我知道两次将控件的BindingContext
正确地设置(调用了OnBindingContextChanged
)自身(TopToolbar
对象)两次-第一次是在没有子视图的情况下,第二次是在添加子视图之后.我检查了BindingContext
是否在所有子控件中正确传播.
From the debugging I know that BindingContext
of a control is set (OnBindingContextChanged
called) properly to itself (TopToolbar
object) twice - first time when there's no child views and second time after they are added. I've checked that BindingContext
is correctly propagated in all child controls.
不幸的是,BackCommand
根本没有绑定. TopToolbar.BackCommand
的setter甚至不会被调用一次.
Unfortunately the BackCommand
is not bind at all. The setter of the TopToolbar.BackCommand
is not called even once.
有趣的是,当我将控件上的BindingContext
设置替换为直接在绑定中直接设置Souce
时,一切正常:
Interestingly when I replace setting the BindingContext
on a control to setting the Souce
directly in bindings everything works fine:
<?xml version="1.0" encoding="UTF-8"?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Core.Controls.TopToolbar"
x:Name="TopToolbarView"
Orientation="Vertical">
<StackLayout Orientation="Horizontal"
HorizontalOptions="FillAndExpand"
<Image Source="{StaticResource Image.Toolbar.LeftArrow}">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={x:Reference TopToolbarView}, Path=BackCommand}" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
</StackLayout>
有什么线索我做错了吗?
Any clue what I do wrong?
推荐答案
它正在按预期方式工作.我建议使用Source
.
It is working as expected. I would recommend using Source
.
在第一种情况下,当您将TopToolbar
上的BindingContext
设置为自身时,那么我想这将是事件的顺序:
In first case, when you set BindingContext
on TopToolbar
to itself, then I would imagine this would be the sequence of events:
-
构造了自定义控件,通过引用将
BindingContext
分配给了self.
页面实例已创建,控件已添加到其中.
Page instance is created, control is added to it.
设置页面的BindingContext
后,通过属性继承的力量,将更新其所有子控件的BindingContext
.
When page's BindingContext
is set, through power of property inheritance, all it's child controls' BindingContext
is updated.
这时,您的自定义控件的BindingContext
仍在引用自身
At this point your custom control's BindingContext
is still referencing itself as value-propagation doesn't override manually set context.
因此,绑定<controls:TopToolbar BackCommand="{Binding MyBackCommand}"
失败,因为此绑定将尝试在其绑定上下文TopToolbar
上查找MyBackCommand
.
Therefore, binding <controls:TopToolbar BackCommand="{Binding MyBackCommand}"
fails, as this binding will try to look for MyBackCommand
on it's binding-context which is TopToolbar
.
但是,在第二种情况下,当在Tapped
命令上将绑定Source
指定为TopToolbar
时,则应该是事件序列:
But, in second case, when you specify binding Source
as TopToolbar
on Tapped
command, then this should be the sequence of events:
-
构造了自定义控件,
BindingContext
为空.
页面实例已创建,控件已添加到其中.
Page instance is created, control is added to it.
设置页面的BindingContext
后,通过属性继承的力量,将更新其所有子控件的BindingContext
,包括您的自定义控件.
When page's BindingContext
is set, through power of property inheritance, all it's child controls' BindingContext
is updated, including your custom control.
这时,您的自定义控件的BindingContext
现在引用了MyCustomersPageModel
.因此,在<controls:TopToolbar BackCommand="{Binding MyBackCommand}"
中的绑定是适当设置的.
At this point your custom control's BindingContext
is now referencing MyCustomersPageModel
. So binding in <controls:TopToolbar BackCommand="{Binding MyBackCommand}"
is appropriately set.
现在,Tapped
绑定不再关心BindingContext
,因为它的源已明确指定,它是父控件TopToolbar
-其BackCommand
又绑定到视图模型的命令.因此,现在将view-model命令绑定到手势识别器的Tapped
命令.而且有效!
Now the Tapped
binding doesn't care about BindingContext
as it's source is explicitly specified, which is parent control TopToolbar
- whose BackCommand
in turn is bound to the view model's command. Hence, the view-model command is now bound to gesture-recognizer's Tapped
command. And it works!
这篇关于自定义Xamarin.Forms控件中的绑定问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!