【问题标题】:Extending WPF application扩展 WPF 应用程序
【发布时间】:2011-02-03 09:32:13
【问题描述】:

我有一个 WPF MVVM 应用程序。我的一个视图有一个用户控件,需要为每个安装进行自定义。它基本上是客户安装的草图,带有一些标签等绑定到视图模型。

现在我的问题是这个用户控件在每个站点/安装上都不同。一种方法是使用 xaml 阅读器从文件/数据库运行时加载 xaml。这可行,但由于我的视图模型是通用的,我必须绑定到方法而不是属性,并且我无法使用 objectdataprovider 加载 xaml。

目前我正在尝试查看是否可以使用 MEF,以便我可以将用户控件创建为插件。所以我现在正在寻找的是:

  1. 如何使用视图/视图模型定义用户控件,以导出 MEF 合同
  2. 我的父视图(在我的 wpf 应用程序中)如何加载导入的用户控件

任何提示都值得赞赏,或者也许有人有不同的方法?

【问题讨论】:

  • 我不明白这条评论:“因为我的视图模型是通用的,所以我必须绑定到方法而不是属性。”什么意思?
  • 假设一个视图绑定到 xCounter。不同的视图绑定到 xCounter 和 yCounter。这些应该以 x 和 y 作为参数绑定到 getCounter(),这样视图模型就不必仅仅因为新的绑定而改变..
  • 在我看来,处理这种差异应该是 ViewModel 的责任,而不是视图的责任。也许您可以发布一些示例 Xaml 和代码来演示?

标签: c# wpf mvvm mef


【解决方案1】:

我建议您结合 MEF 研究 Prism。它具有模块(在您的情况下为插件)和区域(动态加载视图的机制)的概念。

您将能够使用简单的属性导出视图:

[ViewExport(RegionName = RegionNames.MyRegion)]
public partial class MyView : UserControl {
    public MyView() {
        this.InitializeComponent();
    }

    [Import]
    public MyViewModel ViewModel {
        set { DataContext = value; }
    }
}

[Export]
public class MyViewModel : ViewModelBase
[
  ...
}

在您的主应用程序 XAML 中,您将能够像这样导入插件的视图:

<ContentControl Regions:RegionManager.RegionName="{x:Static Infrastructure:RegionNames.MyRegion}"/>

【讨论】:

    【解决方案2】:

    我会考虑的一件事是您需要为每次安装安装自定义视图的设计。相反,我希望使该视图更通用。从长远来看,这将使您的设计更加简单。另外,您正在为每个已安装的基础安装不同的安装设置维护噩梦。

    从您的描述中很难分辨,但听起来 View 是某种对象的集合(某种带有标签或其他东西的绘图)。因此,我会这样对待它。

    我将创建一个基本抽象类来描述您的视图可以显示的每个对象。由于我没有更多信息,我将把这个东西称为“DrawingObject”,因为没有更好的术语。此类将保存视图中所有对象共有的所有信息。请注意,ObservableItem 是一个实现 INotifyPropertyChanged 的​​类,SetProperty 在该基类中设置值并引发 PropertyChanged。

    abstract class DrawingObject : ObservableItem
    {
        Point mPosition;
        public Point Position
        {
            get { return mPosition; }
            set { SetProperty("Position", ref mPosition, value); }
        }
    
        String mLabelText;
        public String LabelText
        {
            get { return mLabelText; }
            set { SetProperty("LabelText", ref mLabelText, value); }
        }
    }
    

    然后,从该基类派生更多自定义对象:

    class Counter : DrawingObject
    {
        public Counter() : base()
        {
        }
    }
    

    然后,您的 ViewModel 将使用基类拥有这些对象的集合。该集合可能是私有的,因为您可能会从构造函数中的某个位置(即数据库、平面文件或...)获取对象

    class ViewModel : ObservableItem
    {
    
        public ViewModel() : base()
        {
            // Call something to populate DrawingObjects property
            PopulateDrawingObjects();
        }
    
        ObservableCollection<DrawingObject> mDrawingObjects = 
            new ObservableCollection<DrawingObject>();
        public ObservableCollection<DrawingObject> DrawingObjects
        {
            get { return mDrawingObjects; }
            private set { mDrawingObjects = value; }
        }
    }
    

    然后,您的视图将绑定到此集合并适当地绘制它们(我将把它留给实施者作为练习)。

    我没有展示的一个扩展是 DrawingObject 可能需要实现适当的序列化功能。

    显然,这是一个粗略的设计草图,可能有一些错误(我是从脑海中完成的),但希望它足以继续。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-29
      • 2016-11-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-06
      • 1970-01-01
      相关资源
      最近更新 更多