2017-09-08 39 views
0

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

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。

有趣的是,当我更换一个控制在绑定的一切直接设置Souce设置BindingContext正常工作:

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

任何线索我做错了什么?

回答

1

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

在第一种情况下,当你TopToolbar给自己设定BindingContext,然后我会想象这将是事件的顺序:

  1. 自定义控制构造,BindingContext通过参考分配给自己。

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

  3. 当页面的BindingContext被设置,通过财产继承的权力,所有它的子控件'BindingContext被更新。

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

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

但是,在第二种情况下,当您指定的Tapped命令结合SourceTopToolbar,那么这应该是事件的顺序:构建

  1. 自定义控制,BindingContext为空。

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

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

  4. 此时您的自定义控件的BindingContext现在引用MyCustomersPageModel。因此在<controls:TopToolbar BackCommand="{Binding MyBackCommand}"中的绑定被适当地设置。

  5. 现在Tapped结合不关心BindingContext,因为它的来源是明确指出,这是家长控制TopToolbar - 又将其BackCommand被绑定到视图模型的命令。因此,view-model命令现在绑定到手势识别器的Tapped命令。它的工作原理!

+0

谢谢您的详细解释! – Marek

+1

太棒了!我希望答案是有帮助的。 – Ada