【问题标题】:How to do some simple layout and operations using WPF with MVVM?如何使用 WPF 和 MVVM 做一些简单的布局和操作?
【发布时间】:2011-10-27 02:26:12
【问题描述】:

我刚开始研究 WPF 和 MVVM,我正在考虑我需要开始使用 MVVM。

我有一个winform应用程序,有一个主面板,在主面板的左边有一些按钮,在主面板的右边是一个放置不同子面板的区域(一次一个面板),单击主窗体按钮后,将调用子面板的方法。

是否可以使用MVVM来做这样的布局和操作?

【问题讨论】:

  • 我必须在新版本中使用WPF,所以不再有winform了

标签: wpf winforms mvvm


【解决方案1】:

主 ViewModel 将包含

的属性
  • ViewModelBase CurrentPage
  • ICommand ChangePageCommand
  • ObservableCollection<ViewModelBase> AvailablePages

主视图将包含

  • ContentControl 用于托管 CurrentPage
  • 屏幕左侧的菜单区域显示AvailablePages
  • 单击菜单区域中的链接将调用ChangePage 命令将CurrentPage 切换到选定的AvailablePage

  • DataTemplates 将用于根据 CurrentPage 中显示的 ChildViewModel 显示 ChildViews

由于主 ViewModel 可以访问所有可用页面,如果需要,它可以在 ChildViewModels 上执行方法,并且可以从 ChildViewModels 调用 ChangePageCommand

如果你有兴趣,我写了一个这样的接口here的例子,虽然它只显示了一个切换CurrentPage的例子,而不是通过AvailablePages导航

【讨论】:

    【解决方案2】:

    很抱歉第一次造成误解。我创建了一个小样本。这是 XAML 代码:

    <Window x:Class="S4SO.ContainerBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="520" Width="425">
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition Height="80" />
          <RowDefinition Height="400" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="400" />
        </Grid.ColumnDefinitions>
        <ContentControl Content="{Binding ContentContent}" Grid.Row="1" Height="400" Width="400" />
        <StackPanel Orientation="Horizontal">
          <Button Content="Use button" Command="{Binding UseButton}" />
          <Button Content="Use Textbox" Command="{Binding UseTextbox}" />
        </StackPanel>
      </Grid>
    </Window>
    

    窗口绑定到一个视图模型,为简单起见,我以 MVVMLight 为基础:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows.Input;
    using System.Windows.Controls;
    using System.Windows;
    using GalaSoft.MvvmLight.Command;
    using GalaSoft.MvvmLight;
    
    namespace S4SO.ContainerBinding {
      public class ViewModel : ViewModelBase {
        private object _ContentContent;
    
        public object ContentContent {
          get { return _ContentContent; }
          set {
            if ( _ContentContent.GetType() == value.GetType() )
                return;
            _ContentContent = value;
            RaisePropertyChanged( "ContentContent" );
          }
        }
    
        public ICommand UseButton { get; set; }
    
        public void CommandUseButton () {
          ContentContent = new Button() {
            Content = "A button",
            Width = 400,
            Height = 400,
            VerticalContentAlignment = VerticalAlignment.Center,
            HorizontalContentAlignment = HorizontalAlignment.Center
          };
        }
    
        public bool CanUseButton () {
          return !( _ContentContent is Button );
        }
    
        public ICommand UseTextbox { get; set; }
    
        public void CommandUseTextbox () {
          ContentContent = new TextBox() {
            Text = "Content here",
            Width = 400,
            Height = 400,
            VerticalContentAlignment = VerticalAlignment.Center,
            HorizontalContentAlignment = HorizontalAlignment.Center
          };
        }
    
        public bool CanUseTextbox () {
          return !( _ContentContent is TextBox );
        }
    
        public ViewModel () {
          _ContentContent = new Label() {
            Content = "Please choose content!",
            Width = 400,
            Height = 400,
            HorizontalContentAlignment = HorizontalAlignment.Center,
            VerticalContentAlignment = VerticalAlignment.Center
          };
          UseButton = new RelayCommand( () => CommandUseButton(), () => CanUseButton() );
          UseTextbox = new RelayCommand( () => CommandUseTextbox(), () => CanUseTextbox() );
        }
    
      }
    }
    

    绝对不是生产级别,但它显示了一个方向,希望现在更符合您的要求。我使用了简单的控件,并没有深入研究绑定那些动态创建的控件。通过代码绑定并不像 XAML 中的绑定语法那样简单。如果这是正确的方向,我会继续告诉你。

    【讨论】:

    • 嗨,Sascha,我可以在右侧区域加载一个默认用户控件,其中包含数据库中的一些数据吗?我正在使用 Interaction.Triggers,但它不起作用。之后,我在那个用户控件中做了一些操作,然后用户控件加载另一个用户控件并带有一些参数来替换自己,我应该向主视图引发一个事件然后在主视图中加载它吗?还有左侧区域的按钮,点击其中一个后,我需要在右侧的用户控件中做一些具体的工作,如何在主视图中调用用户控件的方法?对不起格式:p
    • 加载默认控件:我示例中的标签是默认控件。数据绑定是我提到的尚未深入研究的事情之一。在 MVVM 之后,不应使用 UI 代码中的事件来实现交换,而是通过调用 VM 上的方法来实现。左侧按钮可能会使用命令,VM 会调用用户控件中的方法。在我看来,您拥有充满逻辑的控件:MVVM 的目标之一是减少控件代码隐藏中的逻辑。
    • 谢谢你的建议!
    【解决方案3】:

    当然。左右面板都将绑定到单个 ViewModel(即代表右侧当前面板的 VM)。左侧的按钮将调用 ViewModel 上的操作(可能通过命令)。

    当活动 VM 发生变化时(即,当右侧显示不同的面板时),左侧面板的数据上下文将更改为新 VM。

    您可能需要某种容器 VM 来表示整个窗口,并使用几个子 ViewModel 来表示右侧每个可能的面板。在任何给定时间,只有其中一个被设置为活动面板。这有意义吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-01
      • 1970-01-01
      相关资源
      最近更新 更多