GUI'leri tasarlamak ve uygulamak için bir tür sistematik strateji var mı?


18

Visual Studio C # bir GUI uygulaması oluşturmak için kullanıyorum. Araç Kutusu, düğmeleri ve diğer öğeleri (netlik için "kontrol" demek istediğimde düğmeyi söyleyeceğim) formuma kolayca sürükleyip bırakmamı sağlayan şık bir bileşen paleti olarak hizmet eder, bu da statik formları yapmayı oldukça kolaylaştırır. Ancak, iki sorunla karşılaşıyorum:

  • Düğmeleri ilk etapta oluşturmak çok iş. Statik olmayan bir formum olduğunda (yani düğmeler veya diğer denetimler, kullanıcının ne yaptığına göre çalışma zamanında oluşturulur) hiç paleti kullanamıyorum. Bunun yerine, her düğmeyi manuel olarak, yapıcıyı kullandığım yöntemle çağırarak oluşturmalı ve ardından düğme yüksekliği, genişliği, konumu, etiketi, olay işleyicisi vb. Bu son derece sıkıcı çünkü formun nasıl görüneceğini görmeden tüm bu kozmetik parametrelere bakmam gerekiyor ve ayrıca her düğme için birçok tekrarlayan kod satırı üretiyor.
  • Düğmeleri bir şey yapmak da çok iş. Tam özellikli bir uygulamada etkinliklerle uğraşmak büyük bir acıdır. Bunu nasıl yapacağımı bilmemin tek yolu, bir düğme seçmek, özelliklerindeki olaylar sekmesine gitmek OnClick, olayı Form'kodunda oluşturmak için olayı tıklatmak ve sonra olayın gövdesini doldurmaktır. Mantık ve sunumu ayırmak istediğimden, tüm olay işleyicilerim uygun iş mantığı işlevine tek hatlı çağrılar oluyor. Ancak bunu birçok düğme için kullanmak (örneğin, MS Word gibi bir uygulamada bulunan düğme sayısının) Formdüzinelerce kazan plakası olay işleyici yöntemiyle kodumu kirlettiğini ve bunu korumak zor.

Bunlar nedeniyle, Merhaba Dünya'dan daha karmaşık olan herhangi bir GUI programı benim için gerçekten çok pratik değildir. Açık olmak gerekirse, yazdığım programların en az kullanıcı arayüzüne sahip karmaşıklığı ile ilgili hiçbir sorunum yok - iş mantık kodumu düzgün bir şekilde yapılandırmak için OOP'yi adil bir yeterlilikle kullanabileceğimi hissediyorum. Ama GUI'yi geliştirirken sıkıştım. Çarkı yeniden icat ettiğimi hissediyorum çok sıkıcı görünüyor ve orada bir yerde GUI'yi nasıl düzgün bir şekilde yapacağımı açıklayan bir kitap var.

Bir şey mi kaçırıyorum? Yoksa tüm C # geliştiricileri tekrar eden olay işleyicilerinin ve düğme oluşturma kodunun sonsuz listelerini kabul ediyor mu?


(Umarım faydalı) bir ipucu olarak, iyi bir cevabın aşağıdakilerden bahsedeceğini umuyorum:

  • Tekrarlanan düğme oluşturmayı basitleştirmek için OOP tekniklerini (fabrika modeli gibi) kullanma
  • Birçok olay işleyiciyi Senderhangi düğmenin aradığını belirleyen tek bir yöntemle birleştirmek ve buna göre davranmak
  • XAML ve Windows Forms yerine WPF kullanma

Sen yok olması elbette bunlardan herhangi bahsetmek. Ne tür bir cevap aradığımla ilgili en iyi tahminim.


Gördüğüm gibi evet Fabrika iyi bir desen olurdu ama çok daha doğrudan olaylar yerine kontrollere bağlanmış Komutları ile bir Model-View-Controller desen görüyorum. WPF genellikle MVVM'dir, ancak MVC mümkündür. Şu anda WPF'de MVC kullanan% 90 oranında büyük bir yazılımımız var. Tüm komutlar kontrolöre iletilir ve her şeyi halleder
Franck

Dinamik formu bir GUI düzenleyicisiyle mümkün olan tüm düğmelerle oluşturamaz ve ihtiyacınız olmayan şeyleri dinamik olarak görünmez hale getiremez misiniz? Çok daha az iş gibi geliyor.
Hans-Peter Störr

@hstoerr Ama düzeni çalışmak zor olurdu. Birçok düğme çakışır.
Superbest

Yanıtlar:


22

Bahsettiğiniz bu konularla başa çıkmak için yıllar boyunca gelişen birkaç yöntem vardır; bu konuda, UI çerçevelerinin son yıllarda ele alması gereken iki ana konu olduğunu kabul ediyorum. WPF geçmişinden gelenlere şu şekilde yaklaşılmaktadır:

Zorunlu olmaktan ziyade bildirici tasarım

Kontrolleri somutlaştırmak ve özelliklerini ayarlamak için titizlikle kod yazmayı açıkladığınızda, kullanıcı arayüzü tasarımının zorunlu modelini tarif edersiniz. WinForms tasarımcısıyla bile, sadece bu model üzerinde bir sarıcı kullanıyorsunuz - Form1.Designer.cs dosyasını açın ve tüm bu kodun orada oturduğunu görüyorsunuz.

WPF ve XAML - ve elbette HTML'den itibaren diğer çerçevelerdeki benzer modellerle, düzeninizi tanımlamanız ve çerçevenin uygulamayı ağır bir şekilde kaldırmasına izin vermeniz beklenir. Kullanıcı arabirimi öğeleri arasındaki ilişkiyi tanımlamak için Paneller (Izgara veya WrapPanel vb.) Gibi daha akıllı denetimler kullanırsınız, ancak beklenti, bunları el ile konumlandırmamanızdır. ASP.NET'in Tekrarlayıcı veya WPF'nin ItemsControl gibi tekrarlanabilir kontroller gibi esnek kavramlar, dinamik olarak büyüyen veri varlıklarının dinamik olarak kontrol olarak gösterilmesine izin vererek tekrarlanan kod yazmadan dinamik olarak ölçeklendirme arayüzü oluşturmanıza yardımcı olur.

WPF'nin DataTemplates'i - tekrar, deklaratif olarak - UI iyiliğinin küçük külçelerini tanımlamanıza ve bunları verilerinizle eşleştirmenize izin verir; örneğin, Müşteri veri nesnelerinin bir listesi bir ItemsControl'e bağlı olabilir ve normal bir çalışan (ad ve adresle standart bir ızgara satırı şablonu kullanma) veya bir Ana Müşteri olmasına bağlı olarak farklı bir veri şablonu çağrılabilir. , bir resim ve kolay erişilebilir düğmeler ile görüntülenir. Yine, belirli bir pencerede kod yazmadan , sadece veri bağlamlarının farkında olan daha akıllı kontroller yapar ve böylece bunları verilerinize bağlamanıza ve ilgili işlemleri gerçekleştirmelerine izin vermeniz yeterlidir.

Veri Bağlama ve Komut Ayırma

Veri bağlamaya dokunarak, WPF'nin veri bağlantısı (ve yine AngularJS gibi diğer çerçevelerde de), bir denetimi (örneğin, bir metin kutusu) bir veri varlığıyla (örneğin, Müşterinin Adı) bağlayarak amacınızı belirtmenize ve çerçeve sıhhi tesisat ele. Mantık da benzer şekilde ele alınır. Kod arkasındaki olay işleyicilerini Denetleyici tabanlı iş mantığına el ile bağlamak yerine, denetleyicinin davranışını (örneğin, bir düğmenin Command özelliği) etkinlik külçesini temsil eden bir Komut nesnesine bağlamak için Veri Bağlama mekanizmasını kullanırsınız.

Bu Komutun olay işleyicilerini her seferinde yeniden yazmadan pencereler arasında paylaşılmasını sağlar.

Daha Yüksek Soyutlama Seviyesi

Bu iki çözümün her ikisi de, doğru bir şekilde yorucu bulduğunuz Windows Forms'ın olay odaklı paradigmasından daha yüksek bir soyutlama düzeyine geçişi temsil eder.

Fikir, kontrolün sahip olduğu her bir özelliği ve düğmeden başlayarak her bir davranışı tıklayıp ileriye doğru kodlamak istemediğinizdir. Denetimlerinizin ve altta yatan çerçevenin sizin için daha fazla iş yapmasını ve Veri Bağlama (WinForms'da var olan, ancak WPF'de olduğu kadar kullanışlı olmayan hiçbir soyut kavram) ve UI arasındaki bağlantıları tanımlamak için Komut deseni hakkında daha soyut kavramlar düşünmenize izin vermek istiyorsunuz. ve metale inmeyi gerektirmeyen davranışlar.

MVVM desen bu paradigma Microsoft'un yaklaşımdır. Bunu okumanızı öneririm.

Bu, bu modelin nasıl görüneceğine ve size zamandan ve kod satırlarından nasıl tasarruf edeceğinin kabaca bir örneğidir. Bu derlenmeyecek, ama sözde WPF. :)

Uygulama kaynaklarınızda bir yerde Veri Şablonları tanımlarsınız:

<DataTemplate x:DataType="Customer">
   <TextBox Text="{Binding Name}"/> 
</DataTemplate>

<DataTemplate x:DataType="PrimeCustomer">
   <Image Source="GoldStar.png"/>
   <TextBox Text="{Binding Name}"/> 
</DataTemplate>

Artık ana ekranınızı, verilerinizi açığa çıkaran bir sınıf olan ViewModel'e bağlarsınız. Diyelim ki bir Müşteriler koleksiyonu (sadece a List<Customer>) ve bir Komut nesnesi (yine, türün basit bir ortak özelliği ICommand). Bu bağlantı bağlanmaya izin verir:

public class CustomersnViewModel
{
     public List<Customer> Customers {get;}
     public ICommand RefreshCustomerListCommand {get;}  
}

ve kullanıcı arayüzü:

<ListBox ItemsSource="{Binding Customers}"/>
<Button Command="{Binding RefreshCustomerListCommand}">Refresh</Button>

Ve bu kadar. ListBox'ın sözdizimi, ViewModel dışındaki Müşteriler listesini alır ve bunları kullanıcı arayüzünde oluşturmaya çalışır. Daha önce tanımladığımız iki DataTemplate nedeniyle, ilgili şablonu içe aktarır (DataType'a dayanarak, PrimeCustomer'ın Müşteri'den devraldığını varsayarak) ve ListBox'ın içeriği olarak koyar. Döngü yok, kod aracılığıyla dinamik kontrol üretimi yok.

Düğme, benzer şekilde, davranışını bir ICommand uygulamasına bağlamak için önceden varolan sözdizimine sahiptir, bu da muhtemelen Customersözelliği güncellemeyi bilen - veri bağlama çerçevesini kullanıcı arayüzünü tekrar otomatik olarak güncellemesini ister.

Burada bazı kısayollar aldım elbette, ama bunun özü bu.


5

İlk olarak, bu makale serisini öneriyorum: http://codebetter.com/jeremymiller/2007/07/26/the-build-your-own-cab-series-table-of-contents/ - detay sorunlarını ele almıyor ancak kendi GUI uygulamalarınız için kendi uygulama çerçevenizi tasarlamak ve uygulamak için, MVC, MVP, MVVM'yi tipik Form uygulamanıza nasıl uygulayacağınızı gösteren sistematik bir strateji sunar.

"Olaylarla uğraşmak" hakkındaki sorunuza yanıt vermek: düğmeler benzer şekilde çalışan çok sayıda formunuz varsa, büyük olasılıkla "uygulama çerçevenizde" olay işleyici atamasını kendiniz uygulamak yararlı olacaktır. GUI tasarımcısını kullanarak tıklama etkinliklerini atamak yerine, belirli bir addaki bir düğme için "tıklama" işleyicisinin nasıl adlandırılması gerektiği konusunda bir adlandırma kuralı oluşturun . Örneğin - düğmenin düğmesi MyNiftyButton_ClickHandleriçin MyNiftyButton. Sonra bir formun tüm düğmeleri üzerinde yinelenen yeniden kullanılabilir bir rutin (yansıma kullanarak) yazmak gerçekten zor değildir, formun ilgili bir tıklama işleyicisi içerip içermediğini kontrol edin ve işleyiciyi etkinliğe otomatik olarak atayın. Bir örnek için buraya bakın .

Ve sadece bir grup düğme için sadece bir olay işleyici kullanmak istiyorsanız, bu da mümkün olacaktır. Her olay işleyicisi göndereni geçirdiğinden ve gönderen her zaman basılan düğme olduğundan, her düğmenin "Ad" özelliğini kullanarak iş koduna gönderebilirsiniz.

Düğmelerin (veya diğer denetimlerin) dinamik oluşturulması için: yalnızca bir şablon oluşturmak amacıyla tasarımcıyla kullanılmayan bir biçimde düğmeler veya başka denetimler oluşturabilirsiniz . Ardından, şablon denetimini klonlamak ve yalnızca konum veya boyut gibi özellikleri değiştirmek için yansıma kullanır ( örnek için buraya bakın ). Bu, muhtemelen kodda iki veya üç düzine özelliği manuel olarak başlatmaktan çok daha kolay olacaktır.

Bunu Winform'ları göz önünde bulundurarak yazdım (tıpkı sizin gibi sanırım), ancak genel ilkeler benzer yeteneklere sahip WPF gibi diğer GUI ortamları için geçerli olmalıdır.


Gerçekten de WPF'de yapmak mümkün ve daha da kolay. Sadece komutların bir listesini (önceden kodlanmış özel fonksiyonlar) doldurur ve pencerenizde kaynağı ayarlarsınız. Güzel ve basit bir görsel şablon oluşturuyorsunuz ve tek yapmanız gereken, istediğiniz komutları içeren bir koleksiyonu doldurmak ve büyük WPF bağlaması geri kalanıyla görsel olarak ilgileniyor.
Franck
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.