2010-07-23 74 views
2

我正在尝试使用MVVM,但我无法完全理解它。在这种情况下推荐最佳方法

我有一个视图(窗口),有几个重复的控制。

比方说,我有4个文本框 - 按钮对。他们的行为应该是相同的,按下按钮配对文本框后说:“Hello World!”

我尝试了好几种选择,我能想到的:

  1. 一个视图模型,4个字符串属性绑定到文本框,1个命令
    • 当我每个按钮绑定到相同的命令我不能告诉哪些属性需要设置。
    • 将枚举传递给CommandParameter会感到尴尬。
  2. 一个ViewModel和UserControl承载一个文本框和一个按钮重复4次。
    • 现在我需要公开像Command,CommandParameter,Text等所有属性。似乎很多工作。
    • 仍然不能说点击后需要更新哪些属性。
  3. 每个用户控件都有一个ViewModel
    • 这解决了点击按钮和设置属性,但现在我不知道如何提取从嵌套的ViewModels文本到窗口视图模型。

有没有其他办法?我怀疑DataTemplates可能有用,但我不知道如何。

回答

2

你所描述的是这样一个抽象的和人为的想法,它不保证MVVM。你在谈论TextBox es和Buttons,这些都是'查看',而不是MVVM的思维方式。你几乎总是从一个模型开始。

尽管这里没有'模型'您的规格是从字面上设置TextBox的值为Button点击。看似随机的'4'项目(从无处拾取)和看似无用的TextBox没有任何意义。

把那一边,假设你有一组4个业务实体,每个与他们一个字段是用户可编辑的,并且用户可以触发一个动作,你可以这样做:

  • 创建一个视图模型类来表示一个项目 - 如MyItemModel
  • 创建一个视图模型类来表示一组项目(有可能将只返回第一的集合) - 例如:AllMyItemsListModel

那么对于查看:

  • 创建ItemsControl,与ItemsSource绑定到第二ViewModel类
  • 对于每个ItemTemplate的“集合”的一个实例,有一个模板或UserControl每个项目
  • 在模板或UserControl,将TextBox的Text属性绑定到第一类的相应属性
  • ButtonCommand属性绑定到第一个类的属性,返回ICommand - 使用RelayCommand例如

我不知道你的意思“从嵌套的ViewModels到窗口视图模型提取文本”是什么 - 这是什么意思,你为什么要这么做?

希望有所帮助。

+0

+1表示良好的答案。但我不认为创建ViewModel类来表示模型项的说法是正确的。相反,仅根据视图和视图创建ViewModel类。如果视图需要某些模型数据,那么ViewModel将使用模型中的特定属性来满足视图的需要。因此,第一个ViewModel可以包含文本文本(如果需要,可以从Model获得),Icommand和第二个可以包含'Collection ' – Amsakanna 2010-07-23 22:46:58

+0

感谢您的评论,但我暗示你永远不会启动* app *(而不是视图模型)与视图;你永远不会写一个应用程序'把文本放在方框中',你可以用真正的实体来写一些真正的目的。所以你需要一个Model来开始。我相信我的答案已经表明,第一类将包含文本和ICommand的属性,第二类也将是一个集合。 – 2010-07-24 07:25:07

+0

你是对的我在这里弄错了方法。我现在看到它。但我同意ViewModels应该基于视图而不是Model来创建。 无论如何,在我的情况下,我没有一个集合的固定数量的重复控件,应该在我的模型中表示固定数量的字符串。 – Kugel 2010-07-24 13:43:53

1

Number 3.除了只有一个UserControl和viewmodel,然后是Main页面,该页面上会有多个UserControl实例。如果主窗口需要来自UserControl的信息,则可以通过事件传递它,或者使用类似MVVM Light和它的Messenger类。

1

没有必要为具有如此简单行为的可重用控件创建单独的ViewModel。只需在简单的UserControl中添加一些DependencyProperties和一个事件处理程序,您就可以重用逻辑并仅设置每个实例上实际不同的属性。对于UserControl XAML,您只需将TextBox连接到DependencyProperty并将Button连接到Click处理程序。

<DockPanel> 
    <Button Content="Reset" Click="Button_Click"/> 
    <TextBox Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=Text}"/> 
</DockPanel> 

UserControl的代码只需要定义可以在外部绑定的属性以及用于重置文本的处理程序。

public partial class ResetTextBox : UserControl 
{ 
    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
     "Text", 
     typeof(string), 
     typeof(ResetTextBox), 
     new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); 

    public string Text 
    { 
     get { return (string)GetValue(TextProperty); } 
     set { SetValue(TextProperty, value); } 
    } 

    public static readonly DependencyProperty ResetTextProperty = DependencyProperty.Register(
     "ResetText", 
     typeof(string), 
     typeof(ResetTextBox), 
     new UIPropertyMetadata(String.Empty)); 

    public string ResetText 
    { 
     get { return (string)GetValue(ResetTextProperty); } 
     set { SetValue(ResetTextProperty, value); } 
    } 

    public ResetTextBox() 
    { 
     InitializeComponent(); 
    } 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     Text = ResetText; 
    } 
} 

然后用你只需要绑定到您的视图模型字符串属性和设置,应该在这既可以在这里硬编码,或绑定到其他VM属性重置应用的默认文本的控制。

<StackPanel> 
    <local:ResetTextBox ResetText="One" Text="{Binding Name1}"/> 
    <local:ResetTextBox ResetText="Two" Text="{Binding Name2}"/> 
    <local:ResetTextBox ResetText="Three" Text="{Binding Name3}"/> 
</StackPanel> 
+0

这是我的appreach#2。在你的情况下,你只有两个暴露的属性。在我的情况下,我有4或5,这似乎很多工作,只是暴露属性。 – Kugel 2010-07-24 13:39:24

+0

这不是你在#2中描述的。您的方法需要额外的属性,因为您依赖于ViewModel来完成UserControl在此处执行的工作。如果使用此方法,则没有所有命令函数的额外属性,因为它们不是通过ViewModel中的传递命令来执行,而是由UserControl在内部处理。 – 2010-07-24 16:03:25

+0

你是对的。我喜欢你的答案,因为它很实用。但它不是可测试的。但我想小型UserControls可以。 – Kugel 2010-07-28 13:16:16

相关问题