【发布时间】:2011-10-27 02:26:12
【问题描述】:
我刚开始研究 WPF 和 MVVM,我正在考虑我需要开始使用 MVVM。
我有一个winform应用程序,有一个主面板,在主面板的左边有一些按钮,在主面板的右边是一个放置不同子面板的区域(一次一个面板),单击主窗体按钮后,将调用子面板的方法。
是否可以使用MVVM来做这样的布局和操作?
【问题讨论】:
-
我必须在新版本中使用WPF,所以不再有winform了
我刚开始研究 WPF 和 MVVM,我正在考虑我需要开始使用 MVVM。
我有一个winform应用程序,有一个主面板,在主面板的左边有一些按钮,在主面板的右边是一个放置不同子面板的区域(一次一个面板),单击主窗体按钮后,将调用子面板的方法。
是否可以使用MVVM来做这样的布局和操作?
【问题讨论】:
主 ViewModel 将包含
的属性ViewModelBase CurrentPageICommand ChangePageCommandObservableCollection<ViewModelBase> AvailablePages主视图将包含
ContentControl 用于托管 CurrentPage
AvailablePages 单击菜单区域中的链接将调用ChangePage 命令将CurrentPage 切换到选定的AvailablePage。
DataTemplates 将用于根据 CurrentPage 中显示的 ChildViewModel 显示 ChildViews
由于主 ViewModel 可以访问所有可用页面,如果需要,它可以在 ChildViewModels 上执行方法,并且可以从 ChildViewModels 调用 ChangePageCommand
如果你有兴趣,我写了一个这样的接口here的例子,虽然它只显示了一个切换CurrentPage的例子,而不是通过AvailablePages导航
【讨论】:
很抱歉第一次造成误解。我创建了一个小样本。这是 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 中的绑定语法那样简单。如果这是正确的方向,我会继续告诉你。
【讨论】:
当然。左右面板都将绑定到单个 ViewModel(即代表右侧当前面板的 VM)。左侧的按钮将调用 ViewModel 上的操作(可能通过命令)。
当活动 VM 发生变化时(即,当右侧显示不同的面板时),左侧面板的数据上下文将更改为新 VM。
您可能需要某种容器 VM 来表示整个窗口,并使用几个子 ViewModel 来表示右侧每个可能的面板。在任何给定时间,只有其中一个被设置为活动面板。这有意义吗?
【讨论】: