2012-02-05 46 views
6

WinForms uygulamam için MVVM (Model View ViewModel) desenini uygulamaya çalışıyorum. Ben C# 2005 kullanıyorum.WinForm uygulaması için MVVM Uygulaması

Uygulamam 2 çok satırlı metin kutusu ve 3 düğme ile bir MainForm (Görünüm) vardır. 1. metin kutusunun amacı, düğmeye tıklandığında uygulamanın ne yaptığını gösteren bir yorum göstermektir. Kullanıcılara neler olduğunu güncellemek için TextBox'a satır eklemeye devam ediyorum. 2. metin kutusunun amacı kullanıcıyı herhangi bir hata durumu, çakışma, yinelenen değer hakkında güncellemektir; Kısacası, kullanıcının gözden geçirmesi için gerekli olan her şey. Her mesajı bir INFO veya bir UYARI veya bir HATA olarak sınıflandırır. 3 düğmenin her biri bir eylem gerçekleştirir ve 2 metin kutusunu güncelleştirmeye devam eder.

Bir MainFormViewModel sınıfı oluşturdum.

1. soru: Kullanıcı MainForm'daki düğmeyi tıkladığında, 2 metin kutusunun içeriğini temizlemeli ve düğmeyi, 1. işlem tamamlanıncaya kadar tekrar tıklanmayacak şekilde kapatmam gerekiyor. Bu metin kutusunu ve düğmeyi doğrudan MainForm'da mı yapmalıyım yoksa MainFormViewModel'i bir şekilde kullanmalı mıyım?

2. soru: Düğme tıklatıldığında MainFormViewModel sınıfında bir yöntem çağırılır. Yöntemi çağırmadan önce ve yöntemi çağırdıktan sonra, 1. metin kutusuna "A işleminin başlatılması/sonlandırılması" gibi bir şey göstermek istiyorum. Bunu, bir TextBox'a veya bir dosyaya veya her ikisine de mesaj kaydetmek için bir Günlük yöntemine sahip bir Ortak sınıfı çağırarak yapıyorum. Yine doğrudan MainForm'dan bunu yapmak için tamam olup olmadığını? Olay işleyicisinin başlangıcında ve sonunda bu günlüğe kaydetme yöntemini çağırıyorum.

3. soru: Hata iletilerini ViewModel'den View'a geri nasıl dağıtırım? Özel bir özel durum "TbtException" oluşturdum. Bu yüzden her biri TbtException ve genetik Exception sınıfı için 2 adet catch bloğu yazmalı mıyım?

Teşekkürler.

cevap

3

Yalnızca ViewModel nesnesinin durumuna göre görünümde işlemler gerçekleştirmelisiniz. Örneğin. Bir düğmeyi tıkladığınızda görünüm modelinin hesaplandığını varsaymamalısınız, ancak daha uzun bir şey yaptığını söyleyen görünüm modeline bir durum eklemeniz ve sonra bu durumu görünümde tanımanız gerekir. Görünümdeki düğmeleri istediğiniz gibi devre dışı bırakmamalı veya etkinleştirmemelisiniz, ancak yalnızca bu düğmelerin değiştirilmesini isteyen bir durum varsa. Bu, listedeki hangi öğenin seçili olduğunu belirten bir özelliğe sahip olmak için gidebilir, böylece kullanıcı arabirimi, liste denetiminin SelectedItem üyesini değil, viewmodel'i çağırmaz. Kullanıcı kaldırmayı tıkladığında, görünüm modeli seçilen üyeyi listesinden kaldırır ve görünüm, olaylar biçimindeki durum değişiklikleri aracılığıyla otomatik olarak güncellenir.

Görünümünüz için bir görünüm modeli olarak adlandırıyorum. Mesajları, görüntünün bağlanabileceği gözlenebilir bir koleksiyon yoluyla (örneğin, WinForms'ta iyi bir şekilde desteklenmediğinden, olay olaylarını kaydettiren) ortaya çıkarır. Metin kutusu, herhangi bir zamanda yalnızca koleksiyonun içeriğini oluşturur. Görünümünüzün arayabileceği koleksiyonları temizlemek için eylemleri vardır. Görünüm ayrıca temel modelin eylemlerini de çağırabilir, ancak sadece viewmodel üzerinden güncellenmelidir! Görünüm, temel modelin maruz kaldığı olaylar için herhangi bir olay işleyicisini asla kaydetmemelidir. Bunu yapmak isterseniz, o olayı görünüm modeline bağlamanız ve oraya görüntülemeniz gerekir. Bazen bu, "sadece bir başka indirgeme seviyesi" gibi hissedebilir, bu yüzden sizinki gibi çok basit uygulamalar için aşırı derecede olabilir.

public class MainFormViewModel : INotifyPropertyChanged { 
    private object syncObject = new object(); 

    private MainFormModel model; 
    public virtual MainFormModel Model { 
    get { return model; } 
    set { 
     bool changed = (model != value); 
     if (changed && model != null) DeregisterModelEvents(); 
     model = value; 
     if (changed) { 
     OnPropertyChanged("Model"); 
     if (model != null) RegisterModelEvents(); 
     } 
    } 
    } 

    private bool isCalculating; 
    public bool IsCalculating { 
    get { return isCalculating; } 
    protected set { 
     bool changed = (isCalculating != value); 
     isCalculating = value; 
     if (changed) OnPropertyChanged("IsCalculating"); 
    } 
    } 

    public ObservableCollection<string> Messages { get; private set; } 
    public ObservableCollection<Exception> Exceptions { get; private set; } 

    protected MainFormViewModel() { 
    this.Messages = new ObservableCollection<string>(); 
    this.Exceptions = new ObservableCollection<string>(); 
    } 

    public MainFormViewModel(MainFormModel model) 
    : this() { 
    Model = model; 
    } 

    protected virtual void RegisterModelEvents() { 
    Model.NewMessage += new EventHandler<SomeEventArg>(Model_NewMessage); 
    Model.ExceptionThrown += new EventHandler<OtherEventArg>(Model_ExceptionThrown); 
    } 

    protected virtual void DeregisterModelEvents() { 
    Model.NewMessage -= new EventHandler<SomeEventArg>(Model_NewMessage); 
    Model.ExceptionThrown -= new EventHandler<OtherEventArg>(Model_ExceptionThrown); 
    } 

    protected virtual void Model_NewMessage(object sender, SomeEventArg e) { 
    Messages.Add(e.Message); 
    } 

    protected virtual void Model_ExceptionThrown(object sender, OtherEventArg e) { 
    Exceptions.Add(e.Exception); 
    } 

    public virtual void ClearMessages() { 
    lock (syncObject) { 
     IsCalculating = true; 
     try { 
     Messages.Clear(); 
     } finally { IsCalculating = false; } 
    } 
    } 

    public virtual void ClearExceptions() { 
    lock (syncObject) { 
     IsCalculating = true; 
     try { 
     Exceptions.Clear(); 
     } finally { IsCalculating = false; } 
    } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    protected virtual void OnPropetyChanged(string property) { 
    var handler = PropertyChanged; 
    if (handler != null) handler(this, new PropertyChangedEventArgs(property)); 
    } 
} 

DÜZENLEME: Daha doğrusu görünümünden daha ViewModel durumları yakalamak istiyorum

istisna işleme ile ilgili olarak. Görünüm modeli, onları ekrana hazırlamak için daha uygundur. Bunun WPF'de nasıl çalıştığını bilmiyorum. Bir uygulamayı henüz WPF'de programladım, hala bir çok WinForms yapıyoruz.

Fikirler değişiklik gösterebilir, ancak genel deneme/yakalama cümleleri gerçekten istisna işlemi değildir. UI'nizi çok iyi test etmeyi ve yalnızca gerektiğinde istisna işlemlerini dahil etmeyi tercih ederim. Bu nedenle, bakış modelinizi test ettiğinizde kullanıcı ve kullanıcı testi test edin. Ancak prensibe sadık kalırsanız ve mantıktan uzak durursanız, ünite testleri ile çok şey yapabilirsiniz.

+0

Çok bilgilendirici ve yardımsever. Teşekkürler !! – AllSolutions

+0

Dolayısıyla, 1. soruyla ilgili olarak, görüntünün bir state özelliğini güncellemek için ViewModel'i çağırması gerektiğini ve 2 metin kutusunun bu özelliğe bağlanıp kendilerini temizlemesi gerektiğini mi söylüyorsunuz? Ve ikinci soruyla ilgili olarak, hala açık değil, metin kutusunun çalışan bir yorumu nasıl sürdürmesi gerektiği. ViewModel, bir değişkende yorum yazmayı sürdürmeli ve TextBox bu değişkene bağlanmalı ve kendini güncel tutmalıdır. Üzgünüz, ancak bunu ilk kez uyguluyorum, bu yüzden biraz daha fazla yardım alacağım. Çalışan yorum metninin çok uzun olacağını unutmayın. Herhangi bir Form örneği? – AllSolutions

+0

Hata işleme ile ilgili olarak, formda herhangi bir try catch bloğu olmayacak mı? – AllSolutions