【问题标题】:Refactoring multiple interfaces to a common interface using MVVM, MEF and Silverlight4使用 MVVM、MEF 和 Silverlight4 将多个接口重构为通用接口
【发布时间】:2011-01-31 21:38:15
【问题描述】:

我刚刚使用 MEF 学习 MVVM,并且已经看到了好处,但我对一些实现细节有点困惑。我正在构建的应用程序有几个对不同实体执行相同操作的模型(WCF RIA 服务公开一个实体框架对象),我想避免为我需要的每个视图实现类似的接口/模型,以下是我所拥有的想出虽然它目前不起作用。

公共接口为实现基本模型的每个模型都有一个新的完成事件,这是我可以实现公共类的最简单方法,因为编译器不喜欢从子类型转换为基本类型。

当前的代码可以编译并运行,但它是一个 null IModel,它被传递到 FaqViewModel 类的 [ImportingConstructor] 中。

我有一个如下定义的通用界面(为发布而简化),看过 Shawn Wildermuth 的 RIAXboxGames 示例的人应该对此很熟悉。

public interface IModel
{
    void GetItemsAsync();
    event EventHandler<EntityResultsArgs<faq>> GetFaqsComplete;
}

实现接口的基础方法

public class ModelBase : IModel
{
    public virtual void GetItemsAsync() { }
    public virtual event EventHandler<EntityResultsArgs<faq>> GetFaqsComplete;
    protected void PerformQuery<T>(EntityQuery<T> qry, EventHandler<EntityResultsArgs<T>> evt) where T : Entity
    {
        Context.Load(qry, r =>
        {
            if (evt == null) return;
            try
            {
                if (r.HasError)
                {
                    evt(this, new EntityResultsArgs<T>(r.Error));
                }
                else if (r.Entities.Count() > 0)
                {
                    evt(this, new EntityResultsArgs<T>(r.Entities));
                }
            }
            catch (Exception ex)
            {
                evt(this, new EntityResultsArgs<T>(ex));
            }
        }, null);
    }

    private DomainContext _domainContext;
    protected DomainContext Context
    {
        get
        {
            if (_domainContext == null)
            {
                _domainContext = new DomainContext();
                _domainContext.PropertyChanged += DomainContext_PropertyChanged;
            }

            return _domainContext;
        }
    }

    void DomainContext_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        switch (e.PropertyName)
        {
            case "IsLoading":
                AppMessages.IsBusyMessage.Send(_domainContext.IsLoading);
                break;
            case "IsSubmitting":
                AppMessages.IsBusyMessage.Send(_domainContext.IsSubmitting);
                break;
        }
    }
}

实现基本模型的模型

[Export(ViewModelTypes.FaqViewModel, typeof(IModel))]
public class FaqModel : ModelBase
{
    public override void GetItemsAsync()
    {
        PerformQuery(Context.GetFaqsQuery(), GetFaqsComplete);
    }

    public override event EventHandler<EntityResultsArgs<faq>> GetFaqsComplete;
}

视图模型

[PartCreationPolicy(CreationPolicy.NonShared)]
[Export(ViewModelTypes.FaqViewModel)]
public class FaqViewModel : MyViewModelBase
{
    private readonly IModel _model;

    [ImportingConstructor]
    public FaqViewModel(IModel model)
    {
        _model = model;
        _model.GetFaqsComplete += Model_GetFaqsComplete;

        _model.GetItemsAsync(); // Load FAQS on creation
    }

    private IEnumerable<faq> _faqs;
    public IEnumerable<faq> Faqs
    {
        get { return _faqs; }
        private set
        {
            if (value == _faqs) return;

            _faqs = value;
            RaisePropertyChanged("Faqs");
        }
    }

    private faq _currentFaq;
    public faq CurrentFaq
    {
        get { return _currentFaq; }
        set
        {
            if (value == _currentFaq) return;

            _currentFaq = value;
            RaisePropertyChanged("CurrentFaq");
        }
    }

    public void GetFaqsAsync()
    {
        _model.GetItemsAsync();
    }

    void Model_GetFaqsComplete(object sender, EntityResultsArgs<faq> e)
    {
        if (e.Error != null)
        {
            ErrorMessage = e.Error.Message;
        }
        else
        {
            Faqs = e.Results;
        }
    }
}

最后是 Silverlight 视图本身

public partial class FrequentlyAskedQuestions
{
    public FrequentlyAskedQuestions()
    {
        InitializeComponent();
        if (!ViewModelBase.IsInDesignModeStatic)
        {
            // Use MEF To load the View Model
            CompositionInitializer.SatisfyImports(this);
        }
    }

    [Import(ViewModelTypes.FaqViewModel)]
    public object ViewModel
    {
        set
        {
            DataContext = value;
        }
    }
}

【问题讨论】:

    标签: silverlight visual-studio-2010 mvvm silverlight-4.0 mef


    【解决方案1】:

    似乎我在尝试重构为多个模型时走错了路。如此处所见,http://msdn.microsoft.com/en-us/magazine/dd458800.aspx#id0090019 如果看起来最好的做法是将模型视为通过 RIA 服务引用的 EDMX 类的实例。因此,模型应包含访问 DomainContext 所需的所有方法和事件处理程序。

    如果有人有其他想法,我会向他们敞开心扉。

    【讨论】:

      【解决方案2】:

      作为一个菜鸟,我刚刚开始使用 MEF,我想我已经确定了您的代码可能存在的问题。根据您的问题,听起来您的主要问题是空 IModel 引用。

      尝试改变这个:

      private readonly IModel _model;
      

      到这里:

      [Import]
      public IModel _model { get; set; }
      

      我还没有玩过 MEF 如何喜欢私有和只读属性,因此请尝试设置为 public,然后在您第一次尝试使用时验证 _model 不为空。

      【讨论】:

        猜你喜欢
        • 2017-06-08
        • 2023-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多