2012-10-04 19 views
10

Yapımcı: Son zamanlarda lambda ifadesi ve değişken yakalamalarla garip bir şey yaşadım. Kod, .NET 4.5 (VS2012) kullanan bir WPF/MVVM uygulamasıydı.Neden kurbayı bir alan değişkenine çağırmak zorundayım?

public class MyViewModel : ViewModelBase 
{ 
    public MyViewModel(Action menuCallback) 
    { 
     MyCommand = new RelayCommand(menuCallback); 
    } 

    public MyViewModel(Func<ViewModelBase> viewModelCreator) 
    // I also tried calling the other constructor, but the result was the same 
    // : this(() => SetMainContent(viewModelCreator()) 
    { 
     Action action =() => SetMainContent(viewModelCreator()); 
     MyCommand = new RelayCommand(action); 
    } 

    public ICommand MyCommand { get; private set; } 
} 

: I (bu komut sonra benim görünümünde bir menü öğesi bağlı olacağını)

Özünde bir RelayCommand için kurmayı geri arama benim ViewModel farklı kurucular kullanıyordu, ben aşağıdaki kodu vardı ve daha sonra kullanarak yukarıdaki örneklerini oluşturdu:

// From some other viewmodel's code: 
new MyViewModel(() => new SomeViewModel()); 
new MyViewModel(() => new SomeOtherViewModel()); 

Bu

sonra WPF menü bağlıydı - her menü öğesi veri bağlamında gibi bir MyViewModel örneği vardı. Garip olan şey, menülerin sadece bir kez çalıştığıydı. Hangi ürünlerden hangisini denediğime bakılmaksızın, uygun Func<ViewModelBase>'u arayacaktı - ama sadece bir kez. Başka bir menü öğesini veya aynı öğeyi tekrar seçmeyi denediysem sadece çalışmamıştı. Hiçbir şey VS hata ayıklama çıktısında herhangi bir hata ile ilgili herhangi bir çıkış var ve çıktı.

Ben döngüler içinde değişken yakalar ile sorunların farkındayım, bu yüzden bu yüzden benim VM değiştirildi bu konunun ilişkili olduğunu tahmin yaptı:

public class MyViewModel : ViewModelBase 
{ 
    public MyViewModel(Action buttonCallback) 
    { 
     MyCommand = new RelayCommand(buttonCallback); 
    } 
    private Func<ViewModelBase> _creator; 
    public MyViewModel(Func<ViewModelBase> viewModelCreator) 
    { 
     // Store the Func<> to a field and use that in the Action lambda 
     _creator = viewModelCreator; 
     var action =() => SetMainContent(_creator()); 
     MyCommand = new RelayCommand(action); 
    } 

    public ICommand MyCommand { get; private set; } 
} 

ve aynı şekilde denir. Şimdi her şey gerektiği gibi çalışır.

Sadece eğlence için, ben de MyViewModel yapıcı uygun Action dışında oluşturarak tüm Func<ViewModelBase> yapıcı çalıştı:

// This code also works, even without the _creator field in MyViewModel 
new MyViewModel(() => SetMainContent(new SomeViewModel())); 
new MyViewModel(() => SetMainContent(new SomeOtherViewModel())); 

Bu yüzden çalışma başardı, ama yine de merak ediyorum neden bunu bunun gibi çalışır. Derleyici neden kurucuda Func<ViewModelBase> doğru şekilde yakalamıyor? öyleyse, o zaman ilk yolu çalışmıyor sebebi aslında viewModelCreator değişkeni etrafında kapanış olmadığını ise

+1

İki yaklaşım için oluşturulan IL'deki farklılıklara baktınız mı? Bazı ipuçları verebilir. – nicodemus13

+0

"SetMainContent", "ViewModelBase" sınıfındaysa, son kod örneğindeki lambdada nasıl çalışıyorsunuz? – Pat

+0

SetMainContent, viewmodel örneğini ana pencerenin görünüm modeline göndermek için iletileri (MVVMLight'tan) kullanır. Daha sonra, kullanıcı arayüzünde işlenen bir Content özelliğine atar. Bu sorunu gösteren daha eksiksiz bir kod örneği bulmaya çalışacağım –

cevap

2

aşağıdaki kodu da

public MyViewModel(Func<ViewModelBase> viewModelCreator) 
{ 
    var action =() => { creator = viewModelCreator; SetMainContent(creator()); }; 
    MyCommand = new RelayCommand(action); 
} 

çalışacak tahmin ediyorum, sen' arama sonucu etrafında kapanıyor.

LINQPad'deki kodla hala uğraşıyorum, ancak aslında aynı sorunu alıyorum gibi görünmüyor. Belki de RelayCommand'a özgü bir şey. Daha fazla kod yazabilir misiniz?

+0

Cevabınız için teşekkürler. RelayCommand MVVM'den geliyor: http://bit.ly/QRLCES –

+1

Hmm .. Başka bir bilgisayarda (VS2010 kullanarak) kendi sorgumdan kodu kullanarak yeniden oluşturmaya çalışıyorum ama göremiyorum .. Gitmem gerek orijinal koduma geri dönüp farkın ne olduğunu gör (soru kodum basitleştirildi - ve çok fazla basitleştirdim ve problemi bu süreçte kaldırabilirdim) –

İlgili konular