根据 viewmodel bool 属性 禁用子视图(MVVM 架构)

Disable a subview depending viewmodel bool property (MVVM architecture)

我有一个包含多个子视图 (UserControl) 的视图。

    <StackPanel>
        <local:SubViewGPS/>
        <local:SubViewText/>
    </StackPanel>

此视图绑定到 ViewModel,我想加载或不加载子视图取决于我的 ViewModel 的 bool 属性

    private bool isGPSCompatible;
    public bool IsGPSCompatible {
        get { return isGPSCompatible; }
        set {
            if (isGPSCompatible != value) {
                isGPSCompatible = value;
                NotifyPropertyChanged();
            }
        }
    }

    private bool isTextCompatible;
    public bool IsTextCompatible {
        get { return isTextCompatible; }
        set {
            if (isTextCompatible != value) {
                isTextCompatible = value;
                NotifyPropertyChanged();
            }
        }
    }

我实际上不想 "Disable" 或更改 "Visibility",但如果 属性 为 false,我真的会避免加载组件。根据这个 post: Different views / data template based on member variable DataTemplate 和 DataTrigger 的组合似乎是达到目标的一种方式,但我想知道它是否存在更简单的东西。感谢您的帮助

我终于使用了这个解决方案:

<UserControl x:Class="RLinkClient.LocationView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:client"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">

    <UserControl.Resources>
        <DataTemplate x:Key="GPSLocationViewTemplate">
            <local:GPSControl/>
        </DataTemplate>

        <DataTemplate x:Key="NoGPSViewTemplate">
            <TextBlock Text="GPS Disabled" TextAlignment="Center" VerticalAlignment="Center" FontStyle="Italic" Opacity="0.1" FontWeight="Bold" FontSize="14"/>
        </DataTemplate>
    </UserControl.Resources>
    <Grid>
        <ContentControl>
            <ContentControl.Style>
                <Style TargetType="{x:Type ContentControl}">
                    <Setter Property="ContentTemplate" Value="{StaticResource NoGPSViewTemplate}" />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding GPSCapable}" Value="True">
                            <Setter Property="ContentTemplate" Value="{StaticResource GPSLocationViewTemplate}" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ContentControl.Style>
        </ContentControl>
    </Grid>
</UserControl>

但是如果我可以更改 ViewModel 结构,Frank 的回答是完全可以接受的。

根据条件,我建议在代码中添加视图对象而不是XAML。仅在需要时实例化以避免不必要的初始化例程。也就是说,在检查条件之前不要实例化视图:

 if (IsGPSCompatible )
 myStackPanel.Children.Add((new SubViewGPSView()));

 if (IsTextCompatible )
 myStackPanel.Children.Add((new SubViewText()));

当您使用 MVVM 时,您可以为不同的视图创建单独的子视图模型,并将它们添加到一些 ObservableCollection,具体取决于它们的属性:

<!-- This would replace your StackPanel -->
<ItemsControl ItemsSource="{Binding Capabilities}">
    <ItemsControl.Resources>
        <DataTemplate DataType="localVm:GpsViewModel">
            <local:SubViewGPS />
        </DataTemplate>
        <DataTemplate DataType="localVm:TextViewModel">
            <local:SubViewText />
        </DataTemplate>
        <!-- ... -->
    </ItemsControl.Resources>
</ItemsControl>

您的视图模型中会有一个 ObservableCollection,如下所示:

public ObservableCollection<ICapability> Capabilities { get; private set; }

并根据需要添加实现 ICapability 的子视图模型。