簡體   English   中英

如何使用MVVM在WPF的主窗口中顯示用戶控件

[英]How to display user control within the main window in WPF using 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>

這是另一個窗口(用戶控件-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>

我想使用MVVM模式實現此行為。 我在按鈕EmergencyButton中設置了綁定ShowEmergencyPanel ,以在單擊此按鈕時顯示EmergencyInfo。

任何幫助是極大的贊賞。

你為什么不做導航,像這樣。 為將要插入的圓錐形區域以及將要放置的任何類型的對象放在Windows中。在DataTemplate中將其放置在資源中。

在主要的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>

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
    }

在可以使用DelegateCommand的地方,請檢查如何制作RelayCommand(和通用的)或使用具有自己的DelegateCommand的PRISM。 但是,如果您想使用PRISM,它已經可以導航到區域,可以解決許多問題。 查看來自Brian Lagunas的視頻。

編輯:這是顯示/隱藏網格。 在您設置mainInfo的mainWindow中,您可以以這種方式顯示/隱藏該網格。

在您的MainViewViewModel中,創建一個bool屬性IsVisible

private bool _isVisible;
        public bool IsVisible
        {
            get { return _isVisible; }
            set
            {
                _isVisible = value;
                OnPropertyChanged();
            }
        }

在您的MainView.Resources中將鍵設置為BooleanToVisibilityConverter,例如:

 <BooleanToVisibilityConverter x:Key="Show"/>

以及您要顯示/隱藏的網格可見性:

<Grid x:Name="SomeGridName"
              Grid.Row="1"
              Grid.Colum="1"
              Visibility="{Binding IsVisible,Converter={StaticResource Show}}">

最后將IsVisible屬性設置為某些ToggleButton,僅在true / false之間切換

 <ToggleButton IsChecked="{Binding IsVisible}"
                              Content="ShowGrid" />

這樣,您可以基於IsVisible顯示/隱藏該網格零件,並控制onClick的可見性。 希望能有所幫助。

在您的Window xaml中:

 <ContentPresenter Content="{Binding Control}"></ContentPresenter>

這樣,您的ViewModel必須包含Control屬性。

將您的ViewModel添加到Window的DataContext中。 (例如,在窗口構造函數中, this.Datacontext = new ViewModel();

或使用接口的另一種方式:

 public interface IWindowView
 {
        IUserControlKeeper ViewModel { get; set; }
 }

 public interface IUserControlKeeper 
 {
        UserControl Control { get; set; }
 }


 public partial class YourWindow : IViewWindow
 {
        public YourWindow()
        {
            InitializeComponent();
        }

        public IUserControlKeeper ViewModel
        {
            get
            {
                return (IUserControlKeeper)DataContext;
            }

            set
            {
                DataContext = value;
            }
        }
  }

(以這種方式,在要使用的窗口中初始化您的窗口。服務?)

private IViewWindow _window;
private IViewWindow Window  //or public...
{
  get{
       if(_window==null)
       {
           _window = new YourWindow();
           _window.ViewModel = new YourViewModel();
       }
       return _window;
     }
}

使用您的一個UserControls打開窗口:

  void ShowWindowWithControl(object ControlView, INotifyPropertyChanged ControlViewModel, bool ShowAsDialog)
  {
        if(ControlView is UserControl)
        {       //with interface: Window.ViewModel.Control = ...
               (Window.DataContext as YourViewModel).Control = (UserControl)ControlView;

               if (ControlViewModel != null)
                   (Window.DataContext as YourViewModel).Control.DataContext = ControlViewModel;

               if (ShowAsDialog) //with interface use cast to call the show...
                   Window.ShowDialog();
               else
                   Window.Show();

         }
  }

您可以做的是,將“緊急情況”用戶控件放在MainGrid內,並通過Model屬性控制其可見性。

    <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>


            </Grid>
        </StackPanel>

        <Grid Name="EmergencyPanel">
            <view1:EmergencyInfo x:Name="EmergencyInfoPanel" Visibility={Binding IsEmergencyPanelVisible,Converter={StaticResource BoolToVisibilityConverter}} DataContext={Binding} />
        </Grid>
    </Grid>
    <!--Main Grid-->
</Canvas>

通過為持有用戶控件的Grid設置適當的背景,可以實現模態窗口般的效果。 並且您需要讓IsEmergencyPanelVisible(默認值為false)作為您的模型,並且應該在按鈕單擊命令上將此屬性更改為true。

注意:我猜您對轉換器很熟悉,所以我在解決方案中包含了轉換器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM