Changing ContentTemplate using DataTriggerBehavior

2019-07-18 19:34发布

问题:

I am trying to split out my View into multiple UserControls and then display the appropriate View depending on a certain value.

I accomplish this in WPF like this:

<Window.Resources>
    <DataTemplate x:Key="CardView">
        <views:CardView />
    </DataTemplate>
    <DataTemplate x:Key="OtherView">
        <views:OtherView />
    </DataTemplate>
    <DataTemplate x:Key="MainView">
        <views:MainView />
    </DataTemplate>
</Window.Resources>

...

<ContentControl Content="{Binding}">
    <ContentControl.Style>
        <Style TargetType="{x:Type ContentControl}">
            <Setter Property="ContentTemplate" Value="{StaticResource MainView}" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding CurrentView}" Value="Other">
                    <Setter Property="ContentTemplate" Value="{StaticResource OtherView}" />
                </DataTrigger>
                <DataTrigger Binding="{Binding CurrentView}" Value="Card">
                    <Setter Property="ContentTemplate" Value="{StaticResource CardView}" />
                </DataTrigger>
                <DataTrigger Binding="{Binding CurrentView}" Value="Main">
                    <Setter Property="ContentTemplate" Value="{StaticResource MainView}" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ContentControl.Style>
</ContentControl>

This works great in WPF, and the CurrentView is a string property on the ViewModel that is changed via Button presses/etc.

Since there are no DataTriggers in UWP, I have read that you can accomplish the same thing using DataTriggerBehaviors instead. So I have tried this:

<Page.Resources>
    <DataTemplate x:Key="PaymentView">
        <local:PaymentView />
    </DataTemplate>
    <DataTemplate x:Key="InvoiceView">
        <local:InvoiceView />
    </DataTemplate>
</Page.Resources>

...

<ContentControl Content="{Binding}"
                ContentTemplate="{StaticResource InvoiceView}"
                RelativePanel.AlignLeftWithPanel="True"
                RelativePanel.AlignRightWithPanel="True"
                RelativePanel.Below="PageHeader">
    <interactivity:Interaction.Behaviors>
        <core:DataTriggerBehavior Binding="{x:Bind ViewModel.CurrentView}" Value="Invoice">
            <core:ChangePropertyAction PropertyName="ContentTemplate" Value="{StaticResource InvoiceView}" />
        </core:DataTriggerBehavior>
        <core:DataTriggerBehavior Binding="{x:Bind ViewModel.CurrentView}" Value="Payment">
            <core:ChangePropertyAction PropertyName="ContentTemplate" Value="{StaticResource PaymentView}" />
        </core:DataTriggerBehavior>
    </interactivity:Interaction.Behaviors>
</ContentControl>

But for some reason, the ChangePropertyAction is not firing. I know that the CurrentView is changing, as I have set a breakpoint on it. Just in case, here is the property:

private string _currentView;
public string CurrentView
{
    get { return _currentView; }
    set { Set(ref _currentView, value); }
}

I am using Template10, so all of my ViewModels inherit BindableBase through ViewModelBase, so all the OnPropertyChanged stuff should also be working properly (all other properties are working fine).

Anyway, I know the CurrentView is changing, but the ChangePropertyAction behavior is not firing. Is there something I'm missing?

回答1:

I had assumed that the ContentControl would work using the compiled binding {x:Bind ViewModel.CurrentView} because the designer recognized that binding with AutoComplete.

Once I changed it to use regular binding {Binding CurrentView}, then the trigger started working properly. Here is the working version:

<Page.Resources>
    <DataTemplate x:Key="PaymentView">
        <local:PaymentView />
    </DataTemplate>
    <DataTemplate x:Key="InvoiceView">
        <local:InvoiceView />
    </DataTemplate>
</Page.Resources>

...

<ContentControl Content="{Binding}"
                ContentTemplate="{StaticResource InvoiceView}"
                RelativePanel.AlignLeftWithPanel="True"
                RelativePanel.AlignRightWithPanel="True"
                RelativePanel.Below="PageHeader">
    <interactivity:Interaction.Behaviors>
        <core:DataTriggerBehavior Binding="{Binding CurrentView}" Value="Invoice">
            <core:ChangePropertyAction PropertyName="ContentTemplate" Value="{StaticResource InvoiceView}" />
        </core:DataTriggerBehavior>
        <core:DataTriggerBehavior Binding="{Binding CurrentView}" Value="Payment">
            <core:ChangePropertyAction PropertyName="ContentTemplate" Value="{StaticResource PaymentView}" />
        </core:DataTriggerBehavior>
    </interactivity:Interaction.Behaviors>
</ContentControl>