【问题标题】:Binding issue in custom Xamarin.Forms control自定义 Xamarin.Forms 控件中的绑定问题
【发布时间】:2018-02-17 04:23:52
【问题描述】:

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

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>

我是这样在页面上使用它的:

<pages:ContentPage.Content>
        <StackLayout BackgroundColor="{StaticResource LightGrayColor}"
                     Spacing="0"
                     Padding="0">
            <controls:TopToolbar Title="Master Data" BackCommand="{Binding MyBackCommand}" />

页面的BindingContext是一个视图模型:

public class MyCustomersPageModel
{
    public RelayCommand MyBackCommand { get; set; }

    public MyCustomersPageModel()
    {
        MyBackCommand = // command creation;
    }
}

从调试中我知道控件的BindingContext 被正确设置(OnBindingContextChanged)对其自身(TopToolbar 对象)正确设置了两次——第一次是没有子视图时,第二次是在添加子视图后。我检查了BindingContext 是否在所有子控件中正确传播。

不幸的是,BackCommand 根本没有绑定。 TopToolbar.BackCommand 的 setter 一次都没有被调用。

有趣的是,当我将控件上的 BindingContext 设置替换为直接在绑定中设置 Souce 时,一切正常:

<?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>

知道我做错了什么吗?

【问题讨论】:

    标签: binding xamarin.forms


    【解决方案1】:

    它按预期工作。我建议使用Source

    在第一种情况下,当您将 TopToolbar 上的 BindingContext 设置为自身时,我想这将是事件的顺序:

    1. 自定义控件构建完成,BindingContext通过引用赋值给self。

    2. 页面实例已创建,控件已添加到其中。

    3. 当页面的BindingContext被设置时,通过属性继承的力量,它的所有子控件的BindingContext被更新。

    4. 此时,您的自定义控件的 BindingContext 仍在引用自身 as value-propagation doesn't override manually set context

    5. 因此,绑定&lt;controls:TopToolbar BackCommand="{Binding MyBackCommand}" 失败,因为此绑定将尝试在其绑定上下文(即TopToolbar)上查找MyBackCommand

    但是,在第二种情况下,当您在Tapped 命令上指定绑定SourceTopToolbar 时,这应该是事件序列:

    1. 自定义控件已构建,BindingContext 为空。

    2. 页面实例已创建,控件已添加到其中。

    3. 当页面的BindingContext被设置时,通过属性继承的力量,它的所有子控件的BindingContext被更新,包括你的自定义控件。

    4. 此时您的自定义控件的BindingContext 现在正在引用MyCustomersPageModel。因此,&lt;controls:TopToolbar BackCommand="{Binding MyBackCommand}" 中的绑定设置得当。

    5. 现在Tapped 绑定不再关心BindingContext,因为它的源已明确指定,即父控件TopToolbar - 其BackCommand 又绑定到视图模型的命令。因此,view-model 命令现在绑定到手势识别器的Tapped 命令。它有效!

    【讨论】:

    • 感谢您的详细解释!
    • 太棒了!我希望答案是有帮助的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-29
    • 1970-01-01
    相关资源
    最近更新 更多