WPF / MVVM设计建议

时间:2014-02-10 14:02:42

标签: wpf mvvm

我是WPF的新手,我正在寻找一些指导。

我正在开发一个应用程序,用于打印我们的履行部门的工单。

现在我有2个窗口:第一个是主屏幕,第二个是带有gridview的窗口,用于保存要打印的工单。

第一页上会有几个按钮。每个按钮都会打开第二个窗口;但是,根据单击的按钮,传递到将加载数据的服务的参数将不同。

这样做的最佳做法是什么?

  • 有没有办法在Button控件的某处定义这些参数,然后通过ICommand / RelayCommand传递它们?
  • 我应该创建一个UserControl / ServerControl来让我构建这些额外的属性吗?
  • 我还没想到别的什么?

修改
举一个粗略的例子(这是非常简单的),说我有两套标准:OrderTypes:{Rush,Today,Future}和Locations {Warehouse 1,Warehouse 2,Warehouse 3}

主窗口将有一个3x3网格按钮,每个组合一个。我希望能够在一个按钮“Expedite& Warehouse 1”上指定;然后将这些参数传递回单个方法,这将打开第二个窗口。

4 个答案:

答案 0 :(得分:3)

假设您有MainWindow并且按钮已放入其中。

  1. 为MainWindow创建MainWindowViewModel并将其设置为DataContext

  2. 在ViewModel和绑定按钮Command上使用此ICommand进行ICommand,以便打开另一个窗口的入口点为单个。对于ICommand,您可以使用RelayCommandDelegateCommand,无论哪个最适合您。

  3. 现在,您需要打开窗口并根据按钮类型单击将参数传递给它。我建议让Enum描述需要根据不同按钮执行的动作

  4. <强>枚举

    public enum ActionType
    {
       Action1,
       Action2,
       Action3 and so on...
    }
    

    并从这样的按钮绑定:

    <Button Command="{Binding CommandInstance}"
            CommandParameter="{x:Type local:ActionType.Action1}"/>
    
    <Button Command="{Binding CommandInstance}"
            CommandParameter="{x:Type local:ActionType.Action2}"/>
    

    其中local将是枚举枚举的命名空间。

    在命令中,execute delegate将枚举值传递给另一个窗口构造函数:

    private void CommandMethod(ActionType action)
    {
        AnotherWindow anotherWindow = new AnotherWindow(action);
        anotherWindow.Show();
    }
    

    从构造函数中传递的动作中,您可以检查需要传递给负责加载数据的服务的参数。

    此外,如果从ViewModel创建窗口似乎不正确,您可以在窗口控件上安装Service包装器,它负责显示/关闭窗口。


    <强>更新

    由于您希望从Views传递多个参数,因此为此维护枚举将非常麻烦。您可以使用IMultiValueConverter 从View中传递多个值。

    让我用一个小例子来解释:

    <Button Command="{Binding TestCommand}">
       <Button.Resources>
          <sys:String x:Key="Rush">Rush</sys:String>
          <sys:String x:Key="Warehouse">Warehouse</sys:String>
        </Button.Resources>
        <Button.CommandParameter>
           <MultiBinding Converter="{StaticResource MultiValuesReturnConverter}">
              <Binding Source="{StaticResource Rush}"/>
              <Binding Source="{StaticResource Warehouse}"/>
            </MultiBinding>
        </Button.CommandParameter>
     </Button>
    

    其中sys将是XAML中System的名称空间:

    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    

    所以,现在你可以在XAML中自由地将许多对象从XAML传递给你的命令参数。您所要做的就是在Button资源部分下声明资源,并将其作为绑定传递给转换器。

    转换器代码 将其转换为可作为单个参数对象传递给命令的参数列表:

    public class MultiValuesReturnConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType,
                              object parameter, CultureInfo culture)
        {
            return values.ToList<object>();   
        }
    
        public object[] ConvertBack(object value, Type[] targetTypes,
                                    object parameter, CultureInfo culture)
        {
            throw new System.NotImplementedException();
        }
    }
    

    命令方法:

    private void CommandMethod(object parameter)
    {
        // Now you have all the parameters here to take decision.
        IList<object> values = parameter as List<object>;
    
        AnotherWindow anotherWindow = new AnotherWindow(action);
        anotherWindow.Show();
    }
    

答案 1 :(得分:1)

如果您不想使用某些第三方库,只需将参数通过click事件传递到其他窗口的构造函数中就没有问题。如果您的数据由viewmodel表示,您也可以传递该viewmodel而不是参数本身。

MVVM的一点不是“没有代码隐藏”。很多时候你最终会没有代码隐藏,但尝试以这种方式开发应用程序会导致你进入复杂的反模式,通常比简单的点击事件和“旧方式”更多的工作和更多的代码行。

将您的数据视为数据,尝试在可测试的视图模型中完成所有工作,并且永远不要过于严格地遵循模式,以免最终出现大量不可读的抽象。

答案 2 :(得分:0)

在详细说明任何事情之前,我会建议你使用第三方库MVVMLight,它有许多有用的功能,如Messenger,它自己的RelayCommands等......

  1. 要在按钮中传递参数以在命令中使用它们,如果要传递参数而不管事件的类型如何,如果要传递与某个命令相关的参数,则可以使用Tag属性(事件)然后CommandParameter就是你所需要的:
  2. Tag:获取或设置可用于存储有关此元素的自定义信息的任意对象值。 (继承自FrameworkElement。)

    CommandParameter:

    <Button Content="Parameterized Command" 
        Command="{Binding ParameterizedCommand}" CommandParameter={Binding SomeObject} /> 
    
    1. 除非你有更复杂的场景,否则我不认为你的问题需要创建一个UserControl。
    2. 您可以使用Messenger类将信息从ViewModel传递到另一个(这只是一个独立于MVVM模式的帮助程序)。
    3. MVVMLight具有可帮助您轻松创建ViewModel的代码模板。
    4. MVVMLight有许多有用的片段,您会发现它们很有帮助。
    5. 小心命令,因为它们最初并不支持所有UIElements,它们仅适用于ButtonBase及其子级,它们仅用于替换Click事件,使用Commands和CommandParameters与其他UIElements以及其他类型的事件应该使用一种EventToCommand行为,MVVMLight已经为你做好了准备
    6. 希望我涵盖了您可能需要的最重要的部分。

答案 3 :(得分:0)

最简单直观的方法(使用INotifyPropertyChanged更新用户界面而不是DependencyProperty):

您在[{1}}

中为DataContext创建一个属OrderViewModel的媒体资源
MainWindowViewModel

现在,无论您创建订单视图的方式如何:

  • 您使用所需参数在class MainWindowViewModel : ViewModelBase // ViewModelBase should implement INotifyPropertychanged, unless you're using dependency properties { private OrderViewModel _OrderViewModelInstance; public OrderViewModel OrderViewModelInstance { get{ return _OrderViewModel;} set { _OrderViewModel = value; OnPropertyChanged("OrderViewModel")} // Method from ViewModelBase } (假设点击按钮时)中实例化OrderViewModel
  • 您将订单视图的MainWindowViewModel绑定到XAML中的DataContext。您可能想要创建一个额外的变量,告诉您窗口何时可见。