[英]UI design using MVVM pattern
我正在尝试选择以MVVM方式实现此UI的最佳方法。 我是WPF的新手(比如2个月),但我有很棒的WinForms经验。
这里的ListBox就像一个TabControl(所以它将视图切换到右边),基本上包含表格中显示的项目类型。 所有UI都是动态的(ListBox项,TabItems和Columns在运行时确定)。 该应用程序的目标是WPF和Silverlight。
ViewModel需要的类:
public abstract class ViewModel : INotifyPropertyChanged {}
public abstract class ContainerViewModel : ViewModel
{
public IList<ViewModel> Workspaces {get;set;}
public ViewModel ActiveWorkspace {get;set;}
}
public class ListViewModel<TItem> where TItem : class
{
public IList<TItem> ItemList { get; set; }
public TItem ActiveItem { get; set; }
public IList<TItem> SelectedItems { get; set; }
}
public class TableViewModel<TItem> : ListViewModel<TItem> where TItem : class
{
public Ilist<ColumnDescription> ColumnList { get; set; }
}
现在的问题是如何将其连接到View。
我可以在这里看到两种基本方法:
ListView<T> : UserControl.
接下来,如何连接数据,我在这里看到3种方法(使用XAML或不使用此处无关紧要)。 由于没有简单的DataBinding到DataGrid的Columns或TabControl的TabItems,我看到的方法是:
通过在View中订阅INotifyPropertyChanged来使用手动逻辑:ViewModel.PropertyChanged + = .... ViewModel.ColumnList.CollectionChanged + = ....
使用支持此绑定的自定义控件:我自己编写代码或找到支持此绑定的3d派对控件(我不喜欢这个选项,我的WPF技能太低而无法自己编写代码,我怀疑我会找到免费控件)
更新:28.02.2011事情变得越来越糟糕,我决定使用TreeView而不是ListBox,这是一场噩梦。 您可能猜测TreeView.SelectedItems是一个只读属性,因此没有数据绑定。 嗯,好吧,让我们用旧的方式做,并订阅事件来与viewmodel同步视图。 此时突然发现DisplayMemberPath对TreeView没有任何作用(嗯,好吧让我们以旧的方式使用ToString())。 然后在View的方法中我尝试将ViewModel.SelectedItem与TreeView同步:
private void UpdateTreeViewSelectedItem()
{
//uiCategorySelector.SelectedItem = ReadOnly....
//((TreeViewItem) uiCategorySelector.Items[uiCategorySelector.Items.IndexOf(Model.ActiveCategory)]).IsSelected = true;
// Will not work Items's are not TreeViewItem but Category object......
//((TreeViewItem) uiCategorySelector.ItemContainerGenerator.ContainerFromItem(Model.ActiveCategory)).IsSelected = true;
//Doesn't work too.... NULL // Changind DataContext=Model and Model = new MainViewModel line order doesn't matter.
//Allright.. figure this out later...
}
我所能想到的方法都没有奏效....
这里是我的示例项目的链接,演示了MVVM控制库地狱: http : //cid-b73623db14413608.office.live.com/self.aspx/.Public/MVVMDemo.zip
Maciek的答案实际上比它需要的更复杂。 您根本不需要模板选择器。 要创建异构选项卡控件:
为要作为选项卡项显示的每种视图类型创建视图模型类。 确保每个类都实现一个Text
属性,该属性包含要在其项目的选项卡中显示的文本。
为每个视图模型类创建一个DataTemplate
,将DataType
设置为类的类型,并将模板放在资源字典中。
使用视图模型的实例填充集合。
创建一个TabControl
并将其ItemsSource
绑定到此集合,并添加一个ItemTemplate
,显示每个项目的Text
属性。
这是一个不使用视图模型的示例(并且也没有实现Text
属性,因为我绑定的对象是简单的CLR类型),但是显示了模板选择在此上下文中的工作方式:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:coll="clr-namespace:System.Collections;assembly=mscorlib">
<DockPanel>
<DockPanel.Resources>
<coll:ArrayList x:Key="Data">
<sys:String>This is a string.</sys:String>
<sys:Int32>12345</sys:Int32>
<sys:Decimal>23456.78</sys:Decimal>
</coll:ArrayList>
<DataTemplate DataType="{x:Type sys:String}">
<TextBlock Text="{Binding}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type sys:Int32}">
<StackPanel Orientation="Horizontal">
<TextBlock>This is an Int32:</TextBlock>
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type sys:Decimal}">
<StackPanel Orientation="Horizontal">
<TextBlock>This is a Decimal: </TextBlock>
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</DockPanel.Resources>
<TabControl ItemsSource="{StaticResource Data}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
</DockPanel>
</Page>
当然,在真正的MVVM应用程序中, DataTemplate
将使用UserControl
将每种类型映射到其视图:
<DataTemplate DataType="{x:Type my:ViewModel}">
<my:View DataContext="{Binding}"/>
</DataTemplate>
我写了一篇文章和一个带有源代码的示例应用程序,在那里我讨论并展示了我在这里提到的问题以及如何解决它们。
http://alexburtsev.wordpress.com/2011/03/05/mvvm-pattern-in-silverlight-and-wpf/
要将ViewModel连接到View,您需要分配View的DataContext。 这通常在View的构造函数中完成。
public View()
{
DataContext = new ViewModel();
}
如果您希望在设计时看到视图模型的效果,则需要在XAML中,在View的资源中声明它,为其分配一个键,然后通过StaticResource设置目标的DataContext。
<UserControl
xmlns:vm="clr-namespace:MyViewModels
>
<UserControl.Resources>
<vm:MyViewModel x:Key="MyVM"/>
</UserControl.Resources>
<MyControl DataContext={StaticResource MyVM}/>
</UserControl>
(以上是为了演示设计时的技巧)
由于您正在处理包含TabControl等容器的场景,因此我主张考虑以下事项:
希望有所帮助,如果您有其他问题,请告诉我。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.