使用MVVM,MEF和Silverlight4将多个接口重构为公共接口

时间:2010-03-25 19:28:41

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

我刚学习使用MEF的MVVM并且已经看到了好处,但我对某些实现细节感到有点困惑。我正在构建的应用程序有几个模型,它们与不同的实体(WCF RIA Services公开一个Entity框架对象)做同样的事情,我想避免为我需要的每个视图实现类似的接口/模型,以下是我所拥有的想出来,虽然它目前无效。

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

当前编写的代码编译并运行,但是将一个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;
        }
    }
}

2 个答案:

答案 0 :(得分:0)

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

如果有人有其他想法,我会向他们开放。

答案 1 :(得分:0)

作为一个菜鸟,我刚刚开始玩MEF,我想我已经发现了你的代码可能存在的问题。从您的问题来看,听起来您的主要问题是null IModel引用。

尝试更改此内容:

private readonly IModel _model;

到此:

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

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