【问题标题】:Disable a subview depending viewmodel bool property (MVVM architecture)根据 viewmodel bool 属性禁用子视图(MVVM 架构)
【发布时间】:2015-01-12 22:55:00
【问题描述】:

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

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

此视图绑定到 ViewModel,我想根据我的 ViewModel 的布尔属性加载或不加载子视图

    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();
            }
        }
    }

我实际上不想“禁用”或更改“可见性”,但如果属性为假,我确实避免加载组件。根据这篇文章: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 的回答是完全可以接受的。

【问题讨论】:

  • 为什么切换可见性是个问题?
  • 嗨迈克,这只是优化。这个 View/ViewModel 将被实例化多次,我想限制内存和 CPU 使用率。使用的组件非常重,可见性属性只会隐藏子视图,但仍会在后台加载。

标签: c# wpf mvvm


【解决方案1】:

当您使用 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 的子视图模型。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 不幸的是,这样我打破了 MVVM 模式的所有规则(对不起,我刚刚注意到我没有在我的帖子中准确地描述这些信息,除了标签)
    • 我明白你的意思,但是这个 ViewModel 并不是只用于这个特定的视图,我也用它来编辑另一个视图中的配置。我只是不能将此 ViewModel 耦合到特定视图(这就是为什么我想在完整的 XAML 中实现这一点)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-26
    • 1970-01-01
    • 2021-01-17
    • 1970-01-01
    • 2013-06-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多