如何在 Xamarin Forms 中使用 ControlTemplate 进行替代绑定

How to do alternative binding with ControlTemplate in Xamarin Forms

我正在使用 ControlTemplate 在 Android 和 iOS

之间有一致的导航栏
<ControlTemplate x:Key="NavBarTemplate">
    <StackLayout>
        <StackLayout Orientation="Horizontal" 
            VerticalOptions="CenterAndExpand" 
            IsVisible="{TemplateBinding BindingContext.IsBackButtonVisible, Mode=TwoWay}">
            <Label Text="&lt;" 
                FontSize="Large" 
                FontAttributes="Bold" 
                HorizontalTextAlignment="Center" 
                VerticalOptions="FillAndExpand" 
                VerticalTextAlignment="Center" 
                Margin="20,0,0,0" />
            <Label TextColor="{StaticResource DarkGrey}" 
                HorizontalOptions="StartAndExpand" 
                HorizontalTextAlignment="Center" 
                VerticalOptions="FillAndExpand" 
                VerticalTextAlignment="Center" 
                FontSize="Small" 
                Text="Back" />
            <StackLayout.GestureRecognizers>
                <TapGestureRecognizer Command="{TemplateBinding BindingContext.NavigateBackCommand}" />
            </StackLayout.GestureRecognizers>
        </StackLayout>
        <Image Source="logo.png" 
            VerticalOptions="Center" />
    </StackLayout>
</ControlTemplate>

为了动态显示后退按钮,我在 BasePage.cs

OnAppearing 中添加了以下代码
protected override void OnAppearing () 
{
    base.OnAppearing ();

    if (BindingContext is BaseViewModel viewmodel) 
    {
        if(Application.Current.MainPage as NavigationPage nav)
        {

            if(nav.Navigation.NavigationStack.Count >1 )
            {
                viewmodel.IsBackButtonVisible = true;
            }else
            {
                viewmodel.IsBackButtonVisible = false;
            }
            //dirty coding force to false
            if (!this.IsBackButtonVisible) //refers to local BindableProperty
            {
                viewmodel.IsBackButtonVisible = false;
            }
        }else //no viewmodel found just use localbinding 
        {
            BindingContext = this;
        }
    }
}

所以在某些页面中,即使 NavigationStack > 1

,我也想强制关闭后退按钮

现在我正在基于上面的脏代码实现,方法是在 BasePage 中使用相同的名称 BindableProperty IsBackButtonVisible

我的问题是,有没有办法为 ControlTemplate 做替代绑定,我知道普通绑定有 FallBackValue 和 Default(当然它们只是不绑定的值)但我不想硬编码它似乎 TemplateBinding 不支持那些(智能不会显示这些选项)

我想做的是将 BasePage 中的 BindableProperty 重命名为 ForceNoBackButton 并使导航栏不可见,尽管有 ViewModel 绑定。

有什么方法可以根据条件在 TemplateBinding 中进行替代绑定..

  1. 如果 BindingContext 是 BaseViewModel 的类型,则使用 属性 IsBackButtonVisible

  2. 否则,如果页面 BindingContext 是此页面或 BaseViewModel 以外的其他页面,则回退到 BasePage 本地 BindablePropertyForceNoBackButton

  3. 我可以使用 Bindable属性 的 propertychanged 事件处理程序来实现吗?如果是,如何。如果视觉元素在当前 XAML 中,我知道如何做,不知道如何为 TemplatedView

您可以在 BasePage 上创建两个可绑定属性 IsBackButtonVisibleForceNoBackButton

public static readonly BindableProperty ForceNoBackButtonProperty =
    BindableProperty.Create(
    "ForceNoBackButton", typeof(bool), typeof(BasePage),
    defaultValue: default(bool));

public static readonly BindableProperty IsBackButtonVisibleProperty =
    BindableProperty.Create(
    "IsBackButtonVisible", typeof(bool), typeof(BasePage),
    defaultValue: default(bool));

并更新您的控制模板以简单地使用 IsBackButtonVisible

<ControlTemplate x:Key="NavBarTemplate">
    ...
    <StackLayout Orientation="Horizontal" 
        ..
        IsVisible="{TemplateBinding IsBackButtonVisible}">

同时修改OnAppearing()方法如下:

protected override void OnAppearing()
{
    ..
    if (nav.Navigation.NavigationStack.Count > 1)
    {
        IsBackButtonVisible = !ForceNoBackButton;
    }
    else
    {
        IsBackButtonVisible = false;
    }

要使关联的视图模型与此 属性 保持同步 - 您可以在 BasePage.xaml 上设置绑定,在 [=20] 中添加以下行=] 构造函数以编程方式设置此绑定。

public BasePage()
{
    InitializeComponent();
    SetBinding(IsBackButtonVisibleProperty,
         new Binding(nameof(BaseViewModel.IsBackButtonVisible), 
              mode: BindingMode.OneWayToSource));
}

还建议为 ForceNoBackButton 设置一个 属性-changed 处理程序 - 这样您就可以处理对其值的更改(如果它们发生在页面加载之后)。