Ich bin gerade lernen MVVM mit MEF und sehen bereits die Vorteile, aber ich bin ein wenig verwirrt über einige Details der Implementierung. Die App, die ich baue, hat mehrere Modelle, die das gleiche mit verschiedenen Entitäten tun (WCF RIA Services, die ein Entity-Framework-Objekt aussetzen), und ich möchte vermeiden, eine ähnliche Schnittstelle/Modell für jede Ansicht zu implementieren, die ich benötige, und das Folgende ist, was ich mit gekommen bin, obwohl es derzeit nicht funktioniert.
Die gemeinsame Schnittstelle hat ein neues abgeschlossenes Ereignis für jedes Modell, das das Basismodell implementiert. Dies war der einfachste Weg, wie ich eine gemeinsame Klasse implementieren konnte, da der Compiler kein Casting von einem Kind zum Basistyp mochte.
Der Code, wie es derzeit sitzt kompiliert und läuft, aber die ist ein null IModel in die [ImportingConstructor] für die FaqViewModel-Klasse übergeben.
Ich habe eine gemeinsame Schnittstelle (vereinfacht für Posting) wie folgt definiert, sollte dies vertraut zu denen, die Shawn Wildermuths RIAXboxGames Beispiel gesehen haben.
public interface IModel
{
void GetItemsAsync();
event EventHandler<EntityResultsArgs<faq>> GetFaqsComplete;
}
Eine Basismethode, die die Schnittstelle implementiert
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;
}
}
}
Ein Modell, das das Basismodell implementiert
[Export(ViewModelTypes.FaqViewModel, typeof(IModel))]
public class FaqModel : ModelBase
{
public override void GetItemsAsync()
{
PerformQuery(Context.GetFaqsQuery(), GetFaqsComplete);
}
public override event EventHandler<EntityResultsArgs<faq>> GetFaqsComplete;
}
Ein Ansichtsmodell
[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;
}
}
}
Und dann schließlich die Silverlight-Ansicht selbst
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;
}
}
}