自定义Xamarin.Forms控件中的绑定问题 [英] Binding issue in custom Xamarin.Forms control

查看:91
本文介绍了自定义Xamarin.Forms控件中的绑定问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对自定义控件上的绑定有一个奇怪的问题.我创建了一个自定义工具栏:

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:

  1. 构造了自定义控件,通过引用将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:

  1. 构造了自定义控件,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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆