在MVP-VM事件或按钮单击中使用WPF xaml

时间:2014-12-09 04:19:08

标签: c# wpf xaml icommand

好的,所以我(非常)是WPF的新手,但是有了13年的Win-forms,所以没有新手。 我正在编写一个新系统,并决定使用MVP-VM模式打破WPF,因为我熟悉MVP。

现在我也在重用我自己的(复合)架构,该架构在与Presenters和View模型分开的项目中具有UI或表示层。这种方法的主要好处之一是Presenter层或Base层具有所有表示/命令/控制器逻辑,并且不涉及UI问题。主要IDEA是该层没有引用任何UI组件,如Winforms或WPF。

问题: 在Xaml,我有一个菜单项'退出'我想绑定到View模型。我见过的每个例子都使用ICommand ..它位于Presentation.core中......视图模型位于表示层中,因此没有对Presentation.Core的引用..

到目前为止,Xaml是

<Window x:Class="Homestead.Wpf.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="244" Width="490" xmlns:xcad="http://schemas.xceed.com/wpf/xaml/avalondock">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="23"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="23" />
    </Grid.RowDefinitions>
    <Menu Grid.Row="0">
        <MenuItem Header="File">
            <MenuItem Header="Exit"  />
        </MenuItem> 
    </Menu>
    <StatusBar Grid.Row="2"  >
        <StatusBarItem   >
            <TextBlock  Text="{Binding Path=StatusMessage}" />
        </StatusBarItem>
        <StatusBarItem  HorizontalAlignment="Right" MinWidth="120">
            <TextBlock  Text="{Binding Path=UserName}" />
        </StatusBarItem>
    </StatusBar>
</Grid>

到目前为止的视图模型是

public class ShellViewModel : ViewModelBase
{

    #region Private Variables

    private string _status = string.Empty;
    private string _userName;

    #endregion

    #region Public Properties

    public string StatusMessage
    {
        get { return _status; }
        set
        {
            _status = value;
            OnPropertyChanged("StatusMessage");
        }
    }

    public string UserName
    {
        get { return _userName; }
        set
        {
            _userName = value;
            OnPropertyChanged("UserName");
        }
    }


    #endregion

    #region Commands

    // No reference to ICommand... WTF

    #endregion
}
  1. 是否可以替代此模式..(不使用代码)
  2. 如何使用在运行时添加的菜单项,有趣的是有一种方法。
  3. 我必须重新设计或破坏设计模式才能使用WPF吗?请指导我。

    我可以看到一种可能性,那就是接口ViewModel以及View ..我有一个创建Presenters的Controller,它通常会传递给演示者视图的实现。即,典型的Presenter构造函数将是

        public ErrorMessagePresenter(IErrorMessageView view)
        {
            View = view;
            View.Presenter = this;            
        }
    

    因此控制器代码

        public ErrorMessagePresenter CreateErrorPresenter()
        {
            return new ErrorMessagePresenter(_viewFactory.CreateErrorMessageView());
        }
    

    现在我知道这是相反的,但字面上,UI层只关注UI问题,其他一切包括导航都在Base层或下面处理..

2 个答案:

答案 0 :(得分:2)

WPF中最常见的模式是Model-View-ViewModel,这是一种模式,其中删除了演示者以支持更知识渊博的视图模型,它确实知道像ICommand这样的东西(这是一个契约,共享通过视图层作为一种沟通动作的方式,这证明了视图模型能够了解它。)

您可以尝试通过实现基于UI中的操作在视图模型中执行操作的行为和数据触发器来强制应用程序不使用ICommand,但这需要更多编码,而不仅仅是绑定,并且不可扩展或者如果您打算将来继续开发WPF应用程序(或者通常使用MVVM的Windows应用程序),也可以继续开发。

我建议使用NuGet在项目中加入像MVVM-light这样的框架,这样你就可以从已经适应WPF作为技术的一套完善的类,模式和实用程序的基础上开始。多年来,而不是试图将你熟悉的“球形”框架锤入WPF(比喻性地说)的“方形”空腔。

当我开始学习时,我学到了很多困难,试图将我从WinForms的经验和习惯带到WPF带来的只是麻烦,所以你越早开始和你所做的大部分工作的想法保持平静不适用于WPF,对你的心理健康有好处。

当然,模式是模式,它们可以在多种环境中以不同的方式应用,但实际情况是WPF已经有某些东西的插件以某种方式工作并且试图反对它只是去为了让你作为开发人员和架构师做更多的工作,所以最好是顺应流程并适应XAML世界中最常用的做事方式。

答案 1 :(得分:1)

为您提供一些快速解决方案选项:

  • 1 - 如果您定位System.Windows.Input.ICommand,则Portable Class Library可用。这可能是否可能取决于项目的其他要求,但如果是一个选项,建议您将所有ViewModel和“UI目标”代码放在PCL中,因为根据定义,这些代码是最可重用且与平台无关的您可以在.Net中创建的程序集类型,不仅支持Windows .Net方案,还支持通过Xamarin移动。

  • 2 - 通过依赖注入或服务定位器模式抽象ICommand接口。

  • 3:添加对PresentationCore.dll的引用,但请确保您没有使用ICommand以外的任何内容。


回答你的问题#2,菜单:列表框,组合框,树视图和WPF中任何其他基于项目的UI元素都是从ItemsControl类派生的。它提供了一种从数据项集合中动态生成UI元素的抽象方法。

请参阅this blog series以获得非常全面的解释。 ItemsControl是最强大的WPF功能之一,掌握它可能非常有益。我已经创建了各种各样的东西,从面包屑栏到“标记控件”(类似于StackOverflow的标签选择),到国际象棋板到diagram designers

基本上,您将创建一个具有表示菜单项的简单属性的类(包含文本,图像和单击菜单项时要执行的ICommand),并将此类的实例放入ObservableCollection<T>,它支持WPF数据绑定到集合。


在旁注中,您的Controller会创建演示者和视图,并将视图与ViewModel和Presenter方法以及所有不需要的方法相关联。它创建了一个过于复杂,完全无法维护的场景,您需要在每次需要显示视图时手动执行此操作。

WPF使用DataTemplates解决了这个问题。有关一个非常简单的用法示例,请参阅this answer

事实上,在WPF中甚至根本不需要Presenter的整个概念。由于您的视图使用DataBinding“粘合”到它们的底层ViewModel,因此不需要手动“管道”代码或来回传递数据。