如何使用MVVM在WPF的主窗口中显示用户控件

Jun*_*iuz 1 .net c# wpf xaml mvvm

我有一个WPF应用程序,刚刚开始学习MVVM模式.

我的目标是在我的应用程序中主窗口有一个按钮.单击此按钮时,另一个窗口(或用户控件)将出现在主窗口的顶部.

这是MainWindow.xaml的代码

<Window x:Class="SmartPole1080.View.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:utilities="clr-namespace:SoltaLabs.Avalon.Core.Utilities;assembly=SoltaLabs.Avalon.Core"
    xmlns:userControls="clr-namespace:SoltaLabs.Avalon.View.Core.UserControls;assembly=SoltaLabs.Avalon.View.Core"
    xmlns:controls="clr-namespace:WpfKb.Controls;assembly=SmartPole.WpfKb"
    xmlns:wpf="clr-namespace:WebEye.Controls.Wpf;assembly=WebEye.Controls.Wpf.WebCameraControl"
    xmlns:view="clr-namespace:SmartPole.View;assembly=SmartPole.View"
    xmlns:view1="clr-namespace:SmartPole1080.View"
    xmlns:behaviors="clr-namespace:SoltaLabs.Avalon.Core.Behaviors;assembly=SoltaLabs.Avalon.Core"
    Title="Smart Pole" 
    WindowStartupLocation="CenterScreen"
    Name="mainWindow"
    behaviors:IdleBehavior.IsAutoReset="True" WindowState="Maximized" WindowStyle="None">
<Canvas Background="DarkGray">
    <!--Main Grid-->
    <Grid Width="1080" Height="1920" Background="White" Name="MainGrid"
          HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
        <StackPanel Background="Black">                
            <Grid Background="#253341">
                <Grid.RowDefinitions>
                    <RowDefinition Height="5"/>
                    <RowDefinition Height="*"/>
                    <RowDefinition Height="5"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="5"/>
                    <ColumnDefinition Width="264"/>
                </Grid.ColumnDefinitions>

                <Grid Grid.Row="1" Grid.Column="1">
                    <Button Tag="{StaticResource EmergencyImg}" Name="EmergencyButton"
                            Command="{Binding ShowEmergencyPanel}">
                        <Image Source="{StaticResource EmergencyImg}" />
                    </Button>
                </Grid>

                <!--Emergency Window Dialog-->
                <Grid Name="EmergencyPanel">
                    <view1:EmergencyInfo x:Name="EmergencyInfoPanel"/>
                </Grid>
            </Grid>
        </StackPanel>
    </Grid>
    <!--Main Grid-->
</Canvas>
Run Code Online (Sandbox Code Playgroud)

这是另一个窗口(用户控件 - EmergencyInfo.xaml)

<UserControl x:Class="SmartPole1080.View.EmergencyInfo"
         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:SmartPole1080.View"
         mc:Ignorable="d" 
         d:DesignHeight="1920" d:DesignWidth="1050"
         x:Name="EmergencyInfoPanel">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="50"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <Border Grid.Row="0" BorderBrush="White" Background="White">
        <Button Background="White" BorderThickness="0" FontWeight="Bold" Foreground="Red" 
                HorizontalAlignment="Right" FontSize="25" Margin="0,0,15,0"
                Command="{Binding HideEmergencyPanel}">
            close X
        </Button>
    </Border>
    <Image Grid.Row="1" Source="{StaticResource EdenParkInfoImg}" HorizontalAlignment="Left" />
</Grid>
Run Code Online (Sandbox Code Playgroud)

我想使用MVVM模式实现此行为.我ShowEmergencyPanel在按钮EmergencyButton中设置了绑定,以便在单击此按钮时显示EmergencyInfo.

任何帮助是极大的赞赏.

ivi*_*oke 9

为什么不进行导航,就像这样.为要注入的conetent创建部分,以及您期望将它放在DataTemplate中的Windows.Resources中的任何类型的对象.

在主要的windo xaml

 <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>

    <Window.Resources>
        <DataTemplate DataType="{x:Type home:HomeViewModel}">
            <home:HomeView />
        </DataTemplate>

        <DataTemplate DataType="{x:Type other:OtherViewModel}">
            <other:OtherView />
        </DataTemplate>
    </Window.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid x:Name="Navigation">
            <StackPanel Orientation="Horizontal">
                <Button x:Name="HomeView"
                        Content="Home"
                        Margin="5"
                        Command="{Binding NavigationCommand}"
                        CommandParameter="home" />
                <Button x:Name="Menu"
                        Content="OtherView"
                        Margin="5"
                        Command="{Binding NavigationCommand}"
                        CommandParameter="Other" />
            </StackPanel>
        </Grid>
        <Grid x:Name="MainContent"
              Grid.Row="1">
            <ContentControl Content="{Binding CurrentViewModel}" />
        </Grid>

    </Grid>
Run Code Online (Sandbox Code Playgroud)

MainWindowViewModel看起来像这样.

public class MainWindowViewModel : INotifyPropertyChanged
    {
        private OtherViewModel otherVM;
        private HomeViewModel homeVM;

        public DelegateCommand<string> NavigationCommand { get; private set; }

        public MainWindowViewModel()
        {
            otherVM = new OtherViewModel();
            homeVM = new HomeViewModel();

            // Setting default: homeViewModela.
            CurrentViewModel = homeVM;

            NavigationCommand = new DelegateCommand<string>(OnNavigate);
        }

        private void OnNavigate(string navPath)
        {
            switch (navPath)
            {
                case "other":
                    CurrentViewModel = otherVM;
                    break;
                case "home":
                    CurrentViewModel = homeVM;
                    break;
            }
        }

        private object _currentViewModel;
        public object CurrentViewModel
        {
            get { return _currentViewModel; }
            set
            {
                if (_currentViewModel != value)
                {
                    _currentViewModel = value;
                    OnPropertyChanged();
                }
            }
        }


        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
          PropertyChanged(this, new propertyChangedEventArgs(propertyName));
        }
        #endregion
    }
Run Code Online (Sandbox Code Playgroud)

如果您可以使用DelegateCommand,请检查如何制作RelayCommand(以及通用的)或使用具有自己的DelegateCommand的PRISM.但是如果你想使用PRISM,它已经可以导航到区域,可以解决许多问题.查看Brian Lagunas的视频.

编辑: 这是显示/隐藏网格.在您设置EmergencyInfo的mainWindow中,您可以通过这种方式显示/隐藏该网格.

在你的MainViewViewModel中创建一个bool属性IsVisible

private bool _isVisible;
        public bool IsVisible
        {
            get { return _isVisible; }
            set
            {
                _isVisible = value;
                OnPropertyChanged();
            }
        }
Run Code Online (Sandbox Code Playgroud)

在你的MainView.Resources中设置BooleanToVisibilityConverter的键,如:

 <BooleanToVisibilityConverter x:Key="Show"/>
Run Code Online (Sandbox Code Playgroud)

和您要显示/隐藏设置可见性的网格:

<Grid x:Name="SomeGridName"
              Grid.Row="1"
              Grid.Colum="1"
              Visibility="{Binding IsVisible,Converter={StaticResource Show}}">
Run Code Online (Sandbox Code Playgroud)

最后将IsVisible属性设置为某些ToggleButton,只需在true/false之间切换

 <ToggleButton IsChecked="{Binding IsVisible}"
                              Content="ShowGrid" />
Run Code Online (Sandbox Code Playgroud)

这样,您可以显示/隐藏基于IsVisible的网格部分,并控制onClick的可见性.希望有所帮助.