C # 5 zaman uyumsuzluğuna yeniden giriş çözümleri


16

Yani, bir şey beni C # 5'deki yeni async desteği hakkında rahatsız ediyor:

Kullanıcı zaman uyumsuz işlemi başlatan bir düğmeye basar. Çağrı hemen geri döner ve mesaj pompası tekrar çalışmaya başlar - bütün mesele budur.

Böylece kullanıcı düğmeye tekrar basabilir ve yeniden girişe neden olabilir. Ya bu bir sorunsa?

Gördüğüm demolarda, awaitaramadan önce düğmeyi devre dışı bırakır ve daha sonra tekrar etkinleştirir. Bu bana gerçek dünyadaki bir uygulamada çok kırılgan bir çözüm gibi geliyor.

Belirli bir çalışan işlem kümesi için hangi kontrollerin devre dışı bırakılması gerektiğini belirten bir tür durum makinesini kodlamalı mıyız? Yoksa daha iyi bir yol var mı?

Sadece operasyon süresi boyunca kalıcı bir diyalog göstermeye cazipim, ama bu biraz balyoz kullanmak gibi geliyor.

Parlak fikirleri olan var mı, lütfen?


DÜZENLE:

Bir işlem çalışırken kullanılmaması gereken denetimleri devre dışı bırakmanın kırılgan olduğunu düşünüyorum çünkü üzerinde birçok denetime sahip bir pencereniz olduğunda hızla karmaşık hale geleceğini düşünüyorum. İşleri basit tutmayı seviyorum çünkü hem ilk kodlama hem de sonraki bakım sırasında hata olasılığını azaltır.

Belirli bir işlem için devre dışı bırakılması gereken bir kontrol koleksiyonu varsa ne olur? Peki ya birden fazla işlem aynı anda çalışıyorsa?


Bu konuda kırılgan olan nedir? Kullanıcıya bir şeyin işlendiğine dair bir gösterge verir. Bazı dinamik gösterge çalışmaları işleniyor ve bana çok iyi bir kullanıcı arayüzü gibi görünüyor ekleyin.
Steven Jeuris

Not: .NET 4.5 C # 5 C # 5 denir mi?
Steven Jeuris

1
Sadece bu sorunun neden ÇOK değil burada olduğunu merak ediyor musunuz? Bu kesinlikle kod hakkında yani orada ait olacağını düşünüyorum ...
C. Ross

@ C.Ross, Bu daha çok bir tasarım / kullanıcı arayüzü sorusudur. Burada açıklanması gereken gerçekten teknik bir nokta yoktur.
Morgan Herlocker

Bir kullanıcının gönderme düğmesine bastığı ajax HTML formlarında benzer bir sorunumuz var, bir ajax isteği gönderiliyor ve daha sonra kullanıcının tekrar göndermeyi engellemesini istiyoruz, düğmeyi devre dışı bırakmak bu durumda çok yaygın bir çözümdür
Raynos

Yanıtlar:


14

Yani, C # 5'teki yeni eşzamansız destek hakkında bir şey beni rahatsız ediyor: Kullanıcı bir eşzamansız işlem başlatan bir düğmeye bastı. Çağrı hemen geri döner ve mesaj pompası tekrar çalışmaya başlar - bütün mesele budur. Böylece kullanıcı düğmeye tekrar basabilir ve yeniden girişe neden olabilir. Ya bu bir sorunsa?

Dilde async desteği olmadan bile bunun zaten bir sorun olduğunu belirterek başlayalım . Bir olayı gerçekleştirirken birçok şey mesajların aldatılmasına neden olabilir. Bu durum için zaten savunmacı bir şekilde kod yazmanız gerekiyor; yeni dil özelliği bunu daha açık hale getiriyor , ki bu iyilik.

Bir olay sırasında çalışan ve istenmeyen yeniden girişe neden olan bir mesaj döngüsünün en yaygın kaynağıdır DoEvents. Bunun awaitaksine güzel olan DoEvents, awaityeni görevlerin şu anda çalışan görevleri "aç bırakmayacak" olma ihtimalini arttırmasıdır. DoEventsileti döngüsü pompaları ve buna daha sonra senkronize, geri-girişli olay işleyicisi çağırır awaittipik enqueues gelecekte bir noktada çalışacak şekilde yeni bir görev.

Gördüğüm demolarda, arama beklemeden önce düğmeyi devre dışı bırakır ve daha sonra tekrar etkinleştirir. Bir işlem çalışırken kullanılmaması gereken denetimleri devre dışı bırakmanın kırılgan olduğunu düşünüyorum çünkü üzerinde birçok denetime sahip bir pencereniz olduğunda hızlı bir şekilde karmaşık hale geleceğini düşünüyorum. Belirli bir işlem için devre dışı bırakılması gereken bir kontrol koleksiyonu varsa ne olur? Peki ya birden fazla işlem aynı anda çalışıyorsa?

Bu karmaşıklığı, OO dilinde başka bir karmaşıklığı yönettiğiniz şekilde yönetebilirsiniz: mekanizmaları bir sınıfa soyutlar ve sınıfı bir politikanın doğru bir şekilde uygulanmasından sorumlu hale getirirsiniz . (Mekanizmaları mantıksal olarak politikadan farklı tutmaya çalışın; politikaları, mekanizmalarla aşırı derecede uğraşmadan değiştirmek mümkün olmalıdır.)

İlginç şekillerde etkileşime giren çok sayıda kontrol içeren bir formunuz varsa, o zaman kendi yapımınızın karmaşıklık dünyasında yaşıyorsunuz . Bu karmaşıklığı yönetmek için kod yazmalısınız; Eğer bunu beğenmezseniz , formu o kadar karmaşık olmayacak şekilde basitleştirin.

Sadece operasyon süresi boyunca kalıcı bir diyalog göstermeye cazipim, ama bu biraz balyoz kullanmak gibi geliyor.

Kullanıcılar bundan nefret edecek.


Teşekkürler Eric, sanırım bu kesin cevap - uygulama geliştiricisine kalmış.
Nicholas Butler

6

Düğmeyi neden önce devre dışı bırakıp awaitardından arama tamamlandığında yeniden etkinleştirmenin kırılgan olduğunu düşünüyorsunuz? Düğmenin hiçbir zaman yeniden etkinleştirilmemesinden endişe duyduğunuz için mi?

Arama geri dönmezse, tekrar arama yapamazsınız, bu yüzden istediğiniz davranış budur. Bu, düzeltmeniz gereken bir hata durumunu gösterir. Eşzamansız çağrınız zaman aşımına uğrarsa, bu durum uygulamanızı belirsiz bir durumda bırakabilir - yine düğmenin etkinleştirilmiş olması tehlikeli olabilir.

Bunun dağınık olabileceği tek zaman, bir düğmenin durumunu etkileyen birkaç işlem varsa, ancak bu durumların çok nadir olması gerektiğini düşünüyorum.


Tabii ki hataları işlemek zorundayım
Sorumu

5

Genellikle WPF kullandığım için bunun sizin için geçerli olup olmadığından emin değilim, ancak bunu referans olarak görüyorum ViewModel.

Düğmeyi devre dışı bırakmak yerine, bir IsLoadingbayrak ayarlayın true. Ardından, devre dışı bırakmak istediğiniz herhangi bir UI öğesi bayrağa bağlanabilir. Sonuç, İş Mantıkınızı değil, kendi etkin durumunu çözmek için arayüzün işi haline gelmesidir.

Buna ek olarak, WPF'deki çoğu düğme a'ya bağlıdır ICommandve genellikle ICommand.CanExecuteeşittir !IsLoading, bu nedenle IsLoading true olduğunda komutun otomatik olarak yürütülmesini engeller (ayrıca düğmeyi benim için de devre dışı bırakır)


3

Gördüğüm demolarda, arama beklemeden önce düğmeyi devre dışı bırakır ve daha sonra tekrar etkinleştirir. Bu bana gerçek dünyadaki bir uygulamada çok kırılgan bir çözüm gibi geliyor.

Bu konuda kırılgan bir şey yok ve kullanıcının beklediği şey bu. Kullanıcının düğmeye tekrar basmadan önce beklemesi gerekirse, bekleyin.

Belirli kontrol senaryolarının herhangi bir anda hangi kontrollerin devre dışı bırakılacağı / etkinleştirileceği konusunda karar vermesini nasıl sağlayabilirim, ancak karmaşık bir kullanıcı arayüzünü yönetmenin karmaşık olacağı şaşırtıcı mı? Belirli bir denetimden çok fazla korkunç yan etkiniz varsa, her zaman tüm formu devre dışı bırakabilir ve her şeye bir "yükleme" fırıltısı atabilirsiniz. Her bir kontrolde durum buysa, kullanıcı arayüzünüz muhtemelen ilk etapta çok iyi tasarlanmamıştır (sıkı bağlantı, zayıf kontrol gruplaması, vb.).


Teşekkürler - ama karmaşıklığı nasıl yönetirim?
Nicholas Butler

Seçeneklerden biri, ilgili denetimleri kap içine koymak olabilir. Kontrol konteyneri tarafından değil, kontrol konteyneri tarafından devre dışı bırakılır / etkinleştirilir. ie: EditorControls.Foreach (c => c.Enabled = false);
Morgan Herlocker

2

Widget'ı devre dışı bırakmak en az karmaşık ve hataya açık seçenektir. Zaman uyumsuz işleme başlamadan önce işleyicide devre dışı bırakırsınız ve işlem sonunda yeniden etkinleştirirsiniz. Bu nedenle, her bir denetim için devre dışı bırakma + etkinleştirme, bu denetimin işlenmesinde yerel tutulur.

Bir delege alacak ve kontrol edecek (veya daha fazlasını), denetimleri devre dışı bırakacak ve eşzamansız olarak bir şey çalıştıracak, temsilci yapacak ve denetimleri yeniden etkinleştirecek bir sarıcı bile oluşturabilirsiniz. İstisnalarla ilgilenmelidir (sonunda etkinleştirin), bu nedenle işlem başarısız olursa hala güvenilir bir şekilde çalışır. Ve bunu durum çubuğuna mesaj ekleyerek birleştirebilirsiniz, böylece kullanıcı ne beklediğini bilir.

Devre dışı bırakmaları saymak için bir mantık eklemek isteyebilirsiniz, böylece her ikisi de üçüncü bir işlemi devre dışı bırakacak, ancak birbirini dışlayan olmayan iki işleminiz varsa sistem çalışmaya devam eder. Denetimi iki kez devre dışı bırakırsınız, böylece yalnızca iki kez yeniden etkinleştirirseniz yeniden etkinleştirilir. Vakaları alabildiğiniz kadar ayrı tutarken çoğu vakayı kapsamalıdır.

Öte yandan, devlet makinesi gibi her şey karmaşık hale gelecektir. Deneyimlerime göre, gördüğüm tüm devlet makinelerinin bakımı zordu ve devlet makinenizin tüm diyaloğu kapsaması ve her şeyi her şeye bağlaması gerekecektir.


Teşekkürler - Bu fikri seviyorum. Pencereniz için, her kontrol için devre dışı bırakma ve etkinleştirme isteklerinin sayısını sayan bir yönetici nesneniz olur mu?
Nicholas Butler

@NickButler: Her pencere için zaten bir yönetici nesneniz var - form. Bu yüzden istekleri uygulayan ve sayan bir sınıfım olacak ve sadece ilgili formlara örnekler ekleyeceğim.
Jan Hudec

1

Jan Hudec ve Rachel ilgili fikirleri ifade etseler de, bir Model Görünümü mimarisi gibi bir şey kullanmanızı öneririm - formun bir nesnedeki durumunu ifade eder ve form öğelerini bu duruma bağlarım. Bu, düğmeyi daha karmaşık senaryolar için ölçeklenebilecek şekilde devre dışı bırakır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.