2010-03-28 23 views
24

Genel sorumuz başlık durumları, ViewModel yapımı sırasında veya daha sonra bazı Yüklü olay işleme yoluyla veri yüklemek en iyisi mi?MVVM yükleme verileri?

Cevabın, yüklendikten sonra bazı Yüklü olay işleme yoluyla olduğunu tahmin ediyorum, ancak bunun ViewModel ile View arasında en iyi nasıl koordine edildiğini merak ediyorum. Ben DI Birlik yanı sıra MVVM Işık çerçevesini kullanıyorum

:

İşte benim durum ve özellikle sorun hakkında daha fazla detay Ben çözmeye çalışıyorum bu. İç içe geçmiş Görünümlerim var, her biri karşılık gelen bir ViewModel'e bağlı. ViewModels, her View'nin kök kontrol DataContext'e, Laurent Bugnion'un MVVM Light'e koyduğu ViewModelLocator fikri ile bağlanır. Bu, ViewModel'leri statik bir kaynak yoluyla ve Bağımlılık Enjeksiyon çerçevesi aracılığıyla ViewModels'in ömrünü kontrol etmeyi sağlar, bu durumda Unity. Ayrıca, Expression Blend'in ViewModels ile ilgili her şeyi görmesini ve bunları nasıl bağlayacağını sağlar.

Her neyse, ViewModel'de bir GözlemlenebilirKoleksiyona bir ComboBox veri yoluna sahip bir üst Görünümüm var. ComboBox'ın SelectedItem ayrıca ViewModel'deki bir özelliğe (iki yönlü) bağlıdır. ComboBox seçimi değiştiğinde, bu diğer görünümlerde ve alt gösterimlerde güncellemeleri tetiklemektir. Şu anda MVVM Light'da bulunan Messaging sistemi ile bunu gerçekleştiriyorum. Bu, ComboBox'ta farklı öğeleri seçtiğinizde harika ve beklendiği gibi çalışıyor. Ancak, ViewModel, yapım aşamasında bir dizi başlatma yöntemi çağrısı aracılığıyla verilerini alıyor. Bu, ComboBox'ın ilk SelectedItem'inin ne olduğunu kontrol etmek istiyorsam, sadece bir sorun gibi görünüyor. MVVM Light'ın mesajlaşma sistemini kullanarak, şu anda ViewModel'in SelectedItem özelliğinin ayarlayıcısının güncellemeyi yayınladığı yer ve kurucudaki mesaj için ilgilenen diğer ViewModels kayıtlarını oluşturdum. Görünüşe göre, şu anda SelectedItem'i ViewModel aracılığıyla inşaat zamanında ayarlamaya çalışıyorum; bu da ViewModels'in oluşturulmasına ve kaydedilmesine izin vermemiştir. ViewModel içindeki SelectedItem'in veri yüklemesini ve ilk ayarını koordine etmenin en temiz yolu ne olurdu? Gerçekten de, View'ın kod arkasındaki mantıklı olanı azarlamakla gerçekten uğraşmak istiyorum. ViewModel'ın bir şeylerin ne zaman yüklendiğini bilmesi için bir yola ihtiyacım olduğunu düşünüyorum ve daha sonra verileri yüklemeye ve kurulum aşamasını sonlandırmaya devam edebilirim.

Yanıtlarınız için şimdiden teşekkür ederiz.

+1

Yüklenen olayınız, viewmodel'de bir yöntemi çağırmaz mı? – Klinger

+1

Evet, yapabilirdim. Muhtemelen bunu düşünüyorum. Sanırım bununla ilgili tereddütlerim XAML’de şimdiye dek deklarasyon yapan her şeyi bağlayabildiğim. DataContext'i ayarladıktan sonra üye bağlantılarını tek bir yere ayarladım. Kontrolün Loaded olayının bir ViewModel yöntemine bağlı olmasıyla bunu XAML'de devam ettirmenin temiz bir yolu var mı? Tabii ki ViewModel'in de UI-spesifik olay işleme parametrelerine sahip olması gerektiğini düşünmüyorum. – mkmurray

cevap

23

Olaylar için MVVM Light Toolkit'teki EventToCommand'ı kullanmalısınız. Bunu kullanarak herhangi bir ui öğesinin herhangi bir olayını röle komutuna bağlayabilirsiniz. örneğini indirin

http://blog.galasoft.ch/archive/2009/11/05/mvvm-light-toolkit-v3-alpha-2-eventtocommand-behavior.aspx

de EventToCommand onun makaleyi inceleyin ve bir göz. Bu harika. O zaman herhangi bir kod koduna ihtiyacınız olmayacak.

<Page x:Class="cubic.cats.Wpf.Views.SplashScreenView" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
     xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras" 
     mc:Ignorable="d" 
     d:DesignHeight="300" d:DesignWidth="300" 
    Title="SplashScreenPage"> 

    <i:Interaction.Triggers> 
     <i:EventTrigger EventName="Loaded"> 
      <cmd:EventToCommand Command="{Binding LoadedCommand}" /> 
     </i:EventTrigger>   
    </i:Interaction.Triggers> 

    <Grid> 
     <Label Content="This is test page" /> 
    </Grid> 
</Page> 

ve EventArgs olması görünümü modeli isterseniz görünüm modu bu

public class SplashScreenViewModel : ViewModelBase 
    { 
     public RelayCommand LoadedCommand 
     { 
      get; 
      private set; 
     } 

     /// <summary> 
     /// Initializes a new instance of the SplashScreenViewModel class. 
     /// </summary> 
     public SplashScreenViewModel() 
     { 
      LoadedCommand = new RelayCommand(() => 
      { 
       string a = "put a break point here to see that it gets called after the view as been loaded"; 
      }); 
     } 
    } 

gibi olabilir true yapabilirsiniz basit seti PassEventArgsToCommand, aşağıdaki gibidir: bir örnek

<i:Interaction.Triggers> 
      <i:EventTrigger EventName="Loaded"> 
       <cmd:EventToCommand PassEventArgsToCommand="True" Command="{Binding LoadedCommand}" /> 
    </i:EventTrigger>   
</i:Interaction.Triggers> 

ve görünümü model olacak

public class SplashScreenViewModel : ViewModelBase 
{ 
    public RelayCommand<MouseEventArgs> LoadedCommand 
    { 
     get; 
     private set; 
    } 

    /// <summary> 
    /// Initializes a new instance of the SplashScreenViewModel class. 
    /// </summary> 
    public SplashScreenViewModel() 
    { 
     LoadedCommand = new RelayCommand<MouseEventArgs>(e => 
     { 
      var a = e.WhateverParameters....; 
     }); 
    } 

} 
gibi
+0

Ahh .. MVVM Toolkit ile basit bir mvvm modeli olan bir çözüm arıyorum. Bir tane önerebilir misiniz? Teşekkürler –

1

Sadece ViewModel nesnesindeki bir yöntem olarak View's kök öğesi UserControl DataContext aracılığıyla, yalnızca ViewModel nesnesinde bir yöntem olarak adlandırılan bir Loaded olay işleyicisine bildirilen XAML bağlayıcısına sahip olmaya karar verdim.

Oldukça basit, düz ileri ve temiz bir çözümdü. Yüklenmiş olayı, ViewModel nesnesine, XAML'deki ICommands ile yapabildiğiniz aynı deklarasyonlu şekilde bağlamayı umduğumu sanıyordum.

Klinger'e resmi cevap kredisini vermiş olabilirim, ancak soruma bir yorum göndermedi, bir cevap vermedi. Bu yüzden en azından ona yorumunda bir tane verdim.

0

Bir üst pencere ve bir alt pencere arasındaki mesajlarla çalışırken aynı sorunu yaşadım. ViewModelLocator sınıfınızda görünüm modellerin oluşturulduğu sırayı değiştirin. İletiye bağlı olan tüm görünüm modellerinin, iletiyi gönderen görünüm modelinden önce oluşturulduğundan emin olun. Örneğin

, senin ViewModelLocator sınıfının yapıcısında:

public ViewModelLocator() 
{ 
    if (s_messageReceiverVm == null) 
    { 
     s_messageReceiverVm = new MessageReceiverVM(); 
    } 

    if (s_messageSenderVm == null) 
    { 
     s_messageSenderVm = new MessageSenderVM(); 
    } 
} 
+1

VM'leri ViewModelLocator'da şu şekilde başlatabilirsiniz: 'SimpleIoc.Default.Register (true);' –

+0

Yorumunuzun cevabımla alaka düzeyini anlamıyorum. Lütfen açıklar mısın? – bugged87

+1

ViewModelLocator yapıcısında ViewModels'i oluşturmak için alternatif bir yol önerdim (Ioc kullanarak). –

1

aşağıdaki çözüm zaten sağlanan ve kabul benzer, ancak verilerini yüklemek için görünümü modelinde bir komut kullanmaz ancak bir "normal yöntem". Komutların kullanıcı eylemleri için daha uygun olduğunu düşünüyorum (komutlar kullanılabilir durumda olabilir ve çalışma zamanında kullanılamaz), bu nedenle düzenli bir yöntem çağrısı kullanın, ancak aynı zamanda görünümde bir etkileşim tetikleyicisi ayarlayarak.

Bunu önerebilirim: Görünüm modeli sınıfı oluşturun. Görünüm modeli sınıfını, görünümün xaml'i içinde DataContext özelliğinin içinde oluşturarak örnekleyin.

Verileri görünüm modelinize yüklemek için bir yöntem uygulayın, örn. LoadData. Görünümü kurar, böylece görünüm yüklendiğinde bu yöntem çağrılır.

Görünüm (xaml: Bu görüş modelinde yönteme bağlantısı verilen görünümünde bir etkileşim tetik yapılır ("Microsoft.Expression.Interactions" ve "System.Windows.Interactivity" ihtiyaç vardır atıflar)): görünüşüdür yüklendiğinde

<Window x:Class="MyWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Test" 
    xmlns:viewModel="clr-namespace:ViewModels" 
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"    
    > 
<Window.DataContext> 
    <viewModel:ExampleViewModel/> 
</Window.DataContext> 
<i:Interaction.Triggers> 
    <i:EventTrigger EventName="Loaded"> 
     <ei:CallMethodAction TargetObject="{Binding}" MethodName="LoadData"/> 
    </i:EventTrigger> 
</i:Interaction.Triggers> 

Bu çalışma zamanında ViewModel LoadData yöntemi arayacaktır. Bu, verilerinizi yüklediğiniz yerdir. depoda yöntem zaman uyumsuz yöntem ise

public class ExampleViewModel 
{ 
    /// <summary> 
    /// Constructor. 
    /// </summary> 
    public ExampleViewModel() 
    { 
     // Do NOT do complex stuff here 
    } 


    public void LoadData() 
    { 
     // Make a call to the repository class here 
     // to set properties of your view model 
    } 

, siz de zaman uyumsuz LoadData yöntemini yapabilirsiniz, ancak bu her durumda gerekli değildir. Bu arada, genellikle ben görünüm modelinin yapıcısına veri yüklemeyecektim. Yukarıdaki örnekte, tasarımcının görünümünüzü göstermesi durumunda görünüm modelinin (daha az parametreli) yapıcısı çağrılır. Burada karmaşık şeyler yapmak, tasarımınızı gösterirken tasarımcıda hatalara neden olabilir (aynı sebepten, görüntüleyicide karmaşık şeyler yapmamam için).

Bazı modellerde, görünüm modellerinde kod kurucu, çalışma modelindeki sorunlar, yürütücü modellerin çalıştırıldığı zaman bile sorunlara neden olabilir, görünüm nesnesi tamamen bitmemişken görünümdeki öğelere bağlı olan görünüm modelinin özelliklerini ayarlar. oluşturma.