Я только изучаю MVVM с MEF и уже вижу преимущества, но меня немного смущают некоторые детали реализации. У приложения, которое я создаю, есть несколько Моделей, которые делают то же самое с разными сущностями (службы WCF RIA, представляющие объект инфраструктуры Entity), и я хотел бы избежать реализации аналогичного интерфейса / модели для каждого нужного мне представления, и вот что у меня есть придумать, хотя в настоящее время это не работает.
В общем интерфейсе есть новое завершенное событие для каждой модели, реализующей базовую модель, это был самый простой способ реализовать общий класс, поскольку компилятору не нравилось приведение дочернего к базовому типу.
Код в текущем состоянии компилируется и выполняется, но это пустая IModel, передаваемая в [ImportingConstructor] для класса FaqViewModel.
У меня есть общий интерфейс (упрощенный для публикации), определяемый следующим образом, он должен выглядеть знакомым для тех, кто видел образец 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;
}
}
}