在MVVM中将整个视图更改为另一个用户控件时如何正确设置DataContext

问题描述 投票:0回答:1

当我想将整个视图更改为另一个视图时,我想知道正确的 MVVM 方法是什么。

我主要关心的是将用户控件的

DataContext
设置为首选视图模型。我读到直接设置
DataContext
并不总是最好的主意,所以我想知道我还能怎么做,还有什么替代方案?

我尝试在网上寻找好的解决方案,但到目前为止还没有找到好的答案。

wpf user-controls
1个回答
0
投票

我认为您的问题与在应用程序中实现导航的主题有关。主要有两种方法:

  1. 使用各种页面(在窗口或框架中)和导航方法来更改页面;
  2. 使用不同的 UserControl,根据当前数据上下文的类型显式替换或“自动”替换。

带有显式可更改 UserControl 的简单 UI 导航器示例:

    /// <summary>A type containing a UserControl and its name.</summary>
    public class NameForUC
    {
        /// <summary>Display name.</summary>
        public string DisplayName { get; set; }

        /// <summary>UserControl</summary>
        public UserControl Value { get; set; }
    }
<Window x:Class="CyberForum.UIListBoxNavigator.ListBoxNavigator"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:CyberForum.UIListBoxNavigator"
        mc:Ignorable="d"
        Title="ListBoxNavigator" Height="450" Width="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition Width="4*"/>
        </Grid.ColumnDefinitions>
        <ListBox x:Name="listBox" DisplayMemberPath="DisplayName"
                 SelectedIndex="0">
            <local:NameForUC DisplayName="Begin">
                <local:NameForUC.Value>
                    <local:OnePageUC/>
                </local:NameForUC.Value>
            </local:NameForUC>
            <local:NameForUC DisplayName="End">
                <local:NameForUC.Value>
                    <local:TwoPageUC/>
                </local:NameForUC.Value>
            </local:NameForUC>
        </ListBox>
        <ContentPresenter Grid.Column="1"
                          Content="{Binding SelectedItem, ElementName=listBox}">
            <ContentPresenter.ContentTemplate>
                <DataTemplate DataType="local:NameForUC">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition/>
                        </Grid.RowDefinitions>
                        <TextBlock Text="{Binding DisplayName}" HorizontalAlignment="Center"/>
                        <ContentPresenter Grid.Row="1" Content="{Binding Value}"/>
                    </Grid>
                </DataTemplate>
            </ContentPresenter.ContentTemplate>
        </ContentPresenter>
    </Grid>
</Window>

您可以从这里获取实施细节和带有源代码的项目(俄语主题):https://www.cyberforum.ru/wpf-silverlight/thread2564584.html#post14145160

如果您提供有关任务的更多详细信息和解释,提供 ViewModel 和 View 的最小示例,并解释您希望它们如何交互,我相信您可以获得更具体的建议,以专门针对您的任务选择实现选项。

这是根据当前数据上下文的类型实现视图更改的另一个示例。

namespace Core2023.Navigators
{
    public class LocatorNavigator : ViewModelBase
    {
        public object Current { get => Get<object>(); set => Set(value); }

        public RelayCommand SetCurrent => GetCommand<object>(obj => Current = obj);
    }

    public class TextVM
    {
        public string Text { get; set; } = string.Empty;
    }

    public class NumberVM
    {
        public int Number { get; set; }
    }
}
    <Application.Resources>
        <navigators:TextVM x:Key="textVM" Text="navigators:TextVM x:Key=textVM"/>
        <navigators:NumberVM x:Key="numberVM" Number="999888"/>
        <navigators:LocatorNavigator
            x:Key="navigator"
            Current="{StaticResource textVM}"/>
<UserControl x:Class="Core2023.Navigators.TextUserControl"
             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:Core2023.Navigators"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <d:UserControl.DataContext>
        <local:TextVM Text="Some Text"/>
    </d:UserControl.DataContext>
    <UniformGrid Background="LightYellow"
                 Rows="1">
        <Viewbox>
            <TextBlock Margin="10">
            <Run Text="Text:"/>
            <Run Text="{Binding Text, Mode=OneWay}"/>
            </TextBlock>
        </Viewbox>
        <Viewbox>
        <Button Margin="10"
                Content="Go to NumberVM"
                Command="{Binding SetCurrent, Source={StaticResource navigator}}"
                CommandParameter="{StaticResource numberVM}"/>
        </Viewbox>
    </UniformGrid>
</UserControl>
<UserControl x:Class="Core2023.Navigators.NumberUserControl"
             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:Core2023.Navigators"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <d:UserControl.DataContext>
        <local:NumberVM Number="12345678"/>
    </d:UserControl.DataContext>
    <UniformGrid Background="LightCoral"
                 Rows="1">
        <Viewbox>
            <TextBlock Margin="10">
            <Run Text="Number:"/>
            <Run Text="{Binding Number, Mode=OneWay}"/>
            </TextBlock>
        </Viewbox>
        <Viewbox>
            <Button Margin="10"
                Content="Go to TextVM"
                Command="{Binding SetCurrent, Source={StaticResource navigator}}"
                CommandParameter="{StaticResource textVM}"/>
        </Viewbox>
    </UniformGrid>
</UserControl>
<Window x:Class="Core2023.Navigators.TextNumberWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Core2023.Navigators"
        mc:Ignorable="d"
        Title="TextNumberWindow" Height="450" Width="800"
        Content="{Binding Current, Source={StaticResource navigator}}">
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:TextVM}">
            <local:TextUserControl/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:NumberVM}">
            <local:NumberUserControl/>
        </DataTemplate>
    </Window.Resources>
</Window>

如果数据上下文类型相同,并且需要根据数据上下文属性的值来选择视图,那么最好使用DataTemplateSelector类

© www.soinside.com 2019 - 2024. All rights reserved.