Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Özel panel sınıfı için kod yazmayı, ArrangeOverride ve MeasureOverride yöntemlerini uygulamayı ve Children özelliğini kullanmayı öğrenin.
Önemli API'ler: Panel, ArrangeOverride,MeasureOverride
Örnek kod özel bir panel uygulamasını gösterir, ancak farklı düzen senaryoları için bir paneli nasıl özelleştirebileceğinizi etkileyen düzen kavramlarını açıklamak için çok fazla zaman ayırmıyoruz. Bu düzen kavramları ve bunların belirli düzen senaryonuza nasıl uygulanabileceği hakkında daha fazla bilgi edinmek istiyorsanız bkz. XAML özel panellerine genel bakış.
Panel, XAML düzen sistemi çalıştırıldığında ve uygulama kullanıcı arabiriminiz işlendiğinde içerdiği alt öğeler için düzen davranışı sağlayan bir nesnedir. Panel sınıfından özel bir sınıf türeterek XAML düzeni için özel paneller tanımlayabilirsiniz. ArrangeOverride ve MeasureOverride yöntemlerini geçersiz kılarak, alt öğeleri ölçen ve yerleştiren mantığı sağlayarak paneliniz için davranış sağlarsınız. Bu örnek Panel'den türetilir. Panel'den başladığınızda ArrangeOverride ve MeasureOverride yöntemlerinin başlangıç davranışı yoktur. Kodunuz, alt öğelerin XAML düzen sistemi tarafından tanındığı ve kullanıcı arabiriminde işlendiği ağ geçidini sağlıyor. Bu nedenle kodunuzun tüm alt öğeleri hesaplayıp düzen sisteminin beklediği desenleri takip edebilmesi gerçekten önemlidir.
Düzen senaryonuz
Özel bir panel tanımladığınızda, bir düzen senaryosu tanımlarsınız.
Düzen senaryosu şu şekilde ifade edilir:
- Alt öğelere sahip olduğunda panel ne yapar?
- Panelin kendi alanında kısıtlamaları olduğunda
- Panelin mantığı, sonunda çocukların oluşturulmuş kullanıcı arayüzü düzenine neden olan tüm ölçümleri, yerleşimi, konumları ve boyutlandırmaları nasıl belirler?
Bunu göz önünde bulundurarak, BoxPanel burada gösterilen belirli bir senaryo içindir. Bu örnekte kodu en önde tutma açısından senaryoyu henüz ayrıntılı olarak açıklamayacağız ve bunun yerine gerekli adımlara ve kodlama desenlerine odaklanacağız. Önce senaryo hakkında daha fazla bilgi edinmek istiyorsanız " senaryosuna BoxPanelatlayın ve ardından koda geri dönün.
Panel'den türeterek başlayın
Panel'den özel bir sınıf türeterek başlayın. Bunu yapmanın muhtemelen en kolay yolu, Microsoft Visual Studio'da Add | Yeni Öğe | Class bağlam menüsü seçeneklerini kullanarak Çözüm Gezgini'da bir proje için bu sınıfın ayrı bir kod dosyasını tanımlamaktır. sınıfını (ve dosyasını) BoxPaneladlandırın.
Bir sınıfın şablon dosyası, özel olarak Windows uygulamalarına yönelik olmadığından çok fazla using ifadesi ile başlamaz. İlk olarak using deyimlerini ekleyin. Şablon dosyası, büyük olasılıkla ihtiyacınız olmayan birkaç using deyimiyle de başlar ve silinebilir. Tipik özel panel kodu için ihtiyacınız olan türleri çözümleyebilen using deyimlerinin önerilen listesi aşağıda verilmiştir:
using System;
using System.Collections.Generic; // if you need to cast IEnumerable for iteration, or define your own collection properties
using Windows.Foundation; // Point, Size, and Rect
using Microsoft.UI.Xaml; // DependencyObject, UIElement, and FrameworkElement
using Microsoft.UI.Xaml.Controls; // Panel
using Microsoft.UI.Xaml.Media; // if you need Brushes or other utilities
Artık Panel'i çözümleyebileceğinize göre, temel sınıfı BoxPanelhaline getirin. Ayrıca genel kullanıma açın BoxPanel :
public class BoxPanel : Panel
{
}
Sınıf düzeyinde birkaç mantıksal işleviniz tarafından paylaşılacak, ancak genel bir API olarak kullanıma sunulması gerekmeyen bazı int ve double değerler tanımlayın. Örnekte şunlar adlandırılır: maxrc, rowcount, colcount, , cellwidth, cellheight, maxcellheight, . aspectratio
Bunu yaptıktan sonra, kod dosyasının tamamı şöyle görünür (artık neden elimizde olduğunu bildiğinize göre, kullanımıyla ilgili açıklamalar kaldırılır):
using System;
using System.Collections.Generic;
using Windows.Foundation;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
public class BoxPanel : Panel
{
int maxrc, rowcount, colcount;
double cellwidth, cellheight, maxcellheight, aspectratio;
}
Bu noktadan itibaren, size her seferinde bir üye tanımı göstereceğiz; bu, bir yöntem geçersiz kılma veya bağımlılık özelliği gibi destekleyici bir unsur olabilir. Bunları herhangi bir sırada yukarıdaki iskelete ekleyebilirsiniz.
Ölçü Aşımı
protected override Size MeasureOverride(Size availableSize)
{
// Determine the square that can contain this number of items.
maxrc = (int)Math.Ceiling(Math.Sqrt(Children.Count));
// Get an aspect ratio from availableSize, decides whether to trim row or column.
aspectratio = availableSize.Width / availableSize.Height;
// Now trim this square down to a rect, many times an entire row or column can be omitted.
if (aspectratio > 1)
{
rowcount = maxrc;
colcount = (maxrc > 2 && Children.Count <= maxrc * (maxrc - 1)) ? maxrc - 1 : maxrc;
}
else
{
rowcount = (maxrc > 2 && Children.Count <= maxrc * (maxrc - 1)) ? maxrc - 1 : maxrc;
colcount = maxrc;
}
// Now that we have a column count, divide available horizontal, that's our cell width.
cellwidth = (int)Math.Floor(availableSize.Width / colcount);
// Next get a cell height, same logic of dividing available vertical by rowcount.
cellheight = Double.IsInfinity(availableSize.Height) ? Double.PositiveInfinity : availableSize.Height / rowcount;
foreach (UIElement child in Children)
{
child.Measure(new Size(cellwidth, cellheight));
maxcellheight = (child.DesiredSize.Height > maxcellheight) ? child.DesiredSize.Height : maxcellheight;
}
return LimitUnboundedSize(availableSize);
}
MeasureOverride uygulamasının gerekli deseni, Panel.Children içindeki her bir öğe üzerinde döngü yapmaktır. Her zaman bu öğelerin her birinde Measure yöntemini çağırın. ÖlçününBoyut türünde bir parametresi vardır. Burada belirttiğiniz değer, panelinizin söz konusu alt öğe için kullanılabilir olmasını taahhüt ettiği boyuttur. Bu nedenle, loop yapıp Measure çağrısına başlamadan önce, her hücrenin ne kadar alan ayırabileceğini bilmeniz gerekir. MeasureOverride yönteminin kendisinden availableSize değerine sahipsiniz. Panelin ana öğesi Measure yöntemini çağırdığında kullandığı boyut budur, ve bu, MeasureOverride'in çağrılmasına neden olan tetikleyici durumdu. Bu nedenle tipik bir mantık, her alt öğenin panelin genel kullanılabilirlik alanını böldüğü bir şema oluşturmaktır. Ardından her boyut bölümünü her alt öğenin Ölçüsüne geçirirsiniz.
Boyutun BoxPanel bölünmesi oldukça basittir: alanını çoğunlukla öğe sayısına bağlı olarak bir dizi kutuya böler. Kutular satır ve sütun sayısına ve kullanılabilir boyuta göre boyutlandırılır. Bazen bir kareden bir satır veya sütuna ihtiyaç duyulmaz, bu nedenle bırakılır ve panel satır : sütun oranı bakımından kare yerine dikdörtgene dönüşür. Bu mantığın nasıl geldiği hakkında daha fazla bilgi için "BoxPanel senaryosu" bölümüne atlayın.
Peki ölçü ne yapar? DesiredSize özelliği için, Measure çağrıldığı her öğede salt okunur bir değer ayarlar. DesiredSize değeri, düzenleme geçişine geçtikten sonra büyük olasılıkla önemlidir çünkü DesiredSize, düzenleme sırasında ve son işlemede boyutun ne olabileceğini veya ne olması gerektiğini iletir. DesiredSize'ı kendi mantığınızda kullanmasanız bile sistemin buna ihtiyacı vardır.
AvailableSize'ın yükseklik bileşeni sınırsız olduğunda bu panelin kullanılması mümkündür. Eğer bu doğruysa, panelin bölünecek tanımlı bir yüksekliği yoktur. Bu durumda, ölçüm geçişinin mantığı her bir alt öğeye henüz belirlenmiş bir yüksekliğe sahip olmadığını bildirir. Bunu, Boyut değerini Ölçü çağrısına geçirerek yapar, burada Boyut.Yükseklik sonsuzdur. Bu yasal. Ölçü çağrıldığında, mantık, DesiredSize değerinin aşağıdakilerden en azı olarak ayarlanmış olmasıdır: Measure'a geçirilen değer veya açıkça ayarlanmış Yükseklik ve Genişlik gibi faktörlerden bu öğenin doğal boyutu.
Uyarı
StackPanel'in iç mantığı da bu davranışa sahiptir: StackPanel, alt öğeler üzerinde ölçü'ye sonsuz bir boyut değeri geçirir ve yönlendirme boyutunda alt öğeler üzerinde bir kısıtlama olmadığını belirtir. StackPanel genellikle kendisini dinamik olarak boyutlandırır ve tüm alt öğeleri bu boyutta büyüyen bir yığında barındırır.
Ancak panelin kendisi, MeasureOverride'dan sonsuz değer içeren bir Boyut döndüremez; bu, düzen sırasında bir özel durum oluşturur. Bu nedenle, mantığın bir kısmı, herhangi bir çocuğun istediği en yüksek yüksekliği bulmak ve eğer bu zaten panelin kendi boyut kısıtlamalarından gelmiyorsa, bu yüksekliği hücre yüksekliği olarak kullanmaktır. Yardımcı işlev LimitUnboundedSize, önceki kodda referans alınmıştır; bu işlev maksimum hücre yüksekliğini alır ve panele döndürülecek sonlu bir yükseklik sağlamak için kullanır. Ayrıca, düzenleme geçişi başlatılmadan önce cellheight’in sonlu bir sayı olduğundan emin olunur.
// This method limits the panel height when no limit is imposed by the panel's parent.
// That can happen to height if the panel is close to the root of main app window.
// In this case, base the height of a cell on the max height from desired size
// and base the height of the panel on that number times the #rows.
Size LimitUnboundedSize(Size input)
{
if (Double.IsInfinity(input.Height))
{
input.Height = maxcellheight * rowcount;
cellheight = maxcellheight;
}
return input;
}
YerleştirmeGeçersizKılma
protected override Size ArrangeOverride(Size finalSize)
{
int count = 1;
double x, y;
foreach (UIElement child in Children)
{
x = (count - 1) % colcount * cellwidth;
y = ((int)(count - 1) / colcount) * cellheight;
Point anchorPoint = new Point(x, y);
child.Arrange(new Rect(anchorPoint, child.DesiredSize));
count++;
}
return finalSize;
}
ArrangeOverride uygulamasının gerekli deseni, Panel.Children içindeki her bir öğe üzerinde döngü yapmaktır. Her zaman bu öğelerin her birinde Arrange yöntemini çağırın.
MeasureOverride'daki kadar hesaplama olmadığını unutmayın; Bu tipik bir durum. Alt öğelerin boyutu, panelin kendi MeasureOverride mantığından veya ölçüm geçişi sırasında her bir alt öğenin DesiredSize değerinden zaten bilinir. Ancak yine de panelde her çocuğun görüneceği konuma karar vermemiz gerekir. Tipik bir panelde her alt öğe farklı bir konumda işlenmelidir. Örtüşen öğeler oluşturan bir panel, tipik senaryolar için arzu edilmez (ancak, gerçekten amaçladığınız senaryo bu ise, kasıtlı örtüşmelere sahip paneller oluşturmak seçenek dışı değildir).
Bu panel satır ve sütun kavramına göre düzenlenir. Satır ve sütun sayısı zaten hesaplandı (ölçüm için gerekliydi). Dolayısıyla artık satır ve sütunların şekli ile her hücrenin bilinen boyutları, bu panelin içerdiği her öğe için bir oluşturma konumu tanımlama mantığına katkıda bulunur anchorPoint. Bu Nokta, ölçüden zaten bilinen Boyut ile birlikte, bir Rect oluşturan iki bileşen olarak kullanılır.
Rect , Yerleştir için giriş türüdür.
Panellerin bazen içeriklerini kesmesi gerekir. Böyle bir durumda, kırpılmış boyut DesiredSize'da mevcut olan boyutdur çünkü Ölçü mantığı bunu Ölçü'ye geçirilenlerin en düşük değeri veya diğer doğal boyut faktörleri olarak ayarlar. Bu nedenle, düzenleme sırasında kırpmayı özellikle denetlemeniz gerekmez; kırpma yalnızca DesiredSize'ı her Düzenleme çağrısına geçirme temelinde gerçekleşir.
İşleme konumunu tanımlamak için gerekli tüm bilgiler başka yollarla biliniyorsa, döngüden geçerken her zaman bir sayacı ihtiyacınız yoktur. Örneğin Canvas düzeni mantığında, Alt öğeler koleksiyonundaki konum önemli değildir.
Tuvaldeki her öğeyi konumlandırmak için gereken tüm bilgiler, düzenleme mantığının bir parçası olarak Canvas.Left ve Canvas.Top alt öğelerinin değerlerini okuyarak bilinir. MantığınBoxPanel, yeni bir satıra ne zaman başlayacağı ve y değerinin uzaklığının bilinmesi için colcount ile karşılaştırmak için bir sayı gerekir.
Bir ArrangeOverride uygulamasından döndürdüğünüz finalSize girdi boyutu ile Size değeri genellikle aynıdır olması normaldir. Neden hakkında daha fazla bilgi için XAML özel panellerine genel bakış bölümünün "ArrangeOverride" bölümüne bakın.
İyileştirme: satır sayısı ile sütun sayısını kontrol etme
Bu paneli derleyip şu anda olduğu gibi kullanabilirsiniz. Ancak, bir iyileştirme daha ekleyeceğiz. Az önce gösterilen kodda, mantık ek satırı veya sütunu en boy oranında en uzun olan tarafa yerleştirir. Ancak, hücrelerin şekilleri üzerinde daha fazla kontrol sağlamak için panelin kendi en boy oranı "dikey" olsa bile, 3x4 yerine 4x3 hücre kümesi seçmek tercih edilebilir. Bu nedenle, panel kullanıcısının bu davranışı kontrol edebilmesi için isteğe bağlı bir bağımlılık özelliği ekleyeceğiz. İşte çok temel olan bağımlılık özelliği tanımı:
// Property
public Orientation Orientation
{
get { return (Orientation)GetValue(OrientationProperty); }
set { SetValue(OrientationProperty, value); }
}
// Dependency Property Registration
public static readonly DependencyProperty OrientationProperty =
DependencyProperty.Register(nameof(Orientation), typeof(Orientation), typeof(BoxPanel), new PropertyMetadata(null, OnOrientationChanged));
// Changed callback so we invalidate our layout when the property changes.
private static void OnOrientationChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
if (dependencyObject is BoxPanel panel)
{
panel.InvalidateMeasure();
}
}
Aşağıda, kullanımın Orientation içindeki MeasureOverrideölçü mantığını nasıl etkileyeğini görebilirsiniz. Aslında tek yaptığı, rowcount ve colcount’in maxrc ve gerçek en boy oranından türetilme şeklini değiştirmektir ve bu nedenle her hücre için karşılık gelen boyut farklılıkları vardır.
Orientation (varsayılan) olduğunda, "dikey" dikdörtgen düzenimiz için satır ve sütun sayıları için kullanmadan önce gerçek en boy oranının değerini ters çevirir.
// Get an aspect ratio from availableSize, decides whether to trim row or column.
aspectratio = availableSize.Width / availableSize.Height;
// Transpose aspect ratio based on Orientation property.
if (Orientation == Orientation.Vertical) { aspectratio = 1 / aspectratio; }
BoxPanel senaryosu
için belirli bir senaryo BoxPanel , alanın nasıl bölüneceğinin ana belirleyicilerinden birinin alt öğe sayısını bilmek ve panel için bilinen kullanılabilir alanı bölmek olduğu bir panel olmasıdır. Paneller doğuştan dikdörtgen şekillerdir. Birçok panel, bu dikdörtgen alanını daha fazla dikdörtgene bölerek çalışır; Grid hücreleri için bunu yapar.
Kılavuz durumunda, hücrelerin boyutu ColumnDefinition ve RowDefinition değerlerine göre ayarlanır ve öğeler Grid.Row ve Grid.Column ekli özellikleriyle hangi hücreye yerleştiklerini belirtir.
Grid'den iyi bir düzen elde etmek genellikle önceden alt elemanların sayısını bilmeyi gerektirir, böylece yeterli hücre sağlanır ve her alt eleman kendi hücresine sığacak şekilde ekli özelliklerini ayarlar.
Peki ya çocuk sayısı dinamikse? Bu kesinlikle mümkündür; uygulama kodunuz, kullanıcı arabiriminizi güncelleştirmeye değecek kadar önemli olduğunu düşündüğünüz herhangi bir dinamik çalışma zamanı koşuluna yanıt olarak koleksiyonlara öğeler ekleyebilir. Koleksiyonları/iş nesnelerini yedeklemek için veri bağlama kullanıyorsanız, bu tür güncelleştirmeleri alma ve kullanıcı arabirimini güncelleştirme işlemleri otomatik olarak gerçekleştirilir; bu nedenle genellikle tercih edilen teknik budur (bkz . Ayrıntılı veri bağlama).
Ancak tüm uygulama senaryoları veri bağlamaya uygun değildir. Bazen çalışma zamanında yeni kullanıcı arabirimi öğeleri oluşturmanız ve bunları görünür hale getirmeniz gerekir.
BoxPanel bu senaryoya yöneliktir.
BoxPanel, hesaplamalarda alt öğe sayısını kullandığından, değişen alt öğe sayısı sorun oluşturmaz ve hem mevcut hem de yeni alt öğeleri yeni bir düzende ayarlayarak bunların tümünün sığmasını sağlar.
Daha fazla genişletmeye BoxPanel yönelik gelişmiş bir senaryo (burada gösterilmez) hem dinamik alt öğeleri barındırabilir hem de tek tek hücrelerin boyutlandırılması için daha güçlü bir faktör olarak bir çocuğun DesiredSize özelliğini kullanabilir. Bu senaryo, daha az boş alan olması için değişken satır veya sütun boyutları ya da kılavuz dışı şekiller kullanabilir. Bu, çeşitli boyutlarda ve en boy oranlarında birden çok dikdörtgenin hem estetik hem de en küçük boyut için içeren bir dikdörtgene nasıl sığabileceğine yönelik bir strateji gerektirir.
BoxPanel bunu yapmaz; alanı bölmek için daha basit bir teknik kullanıyor.
BoxPanel'nin tekniği, çocuk sayısından daha büyük olan en küçük kare sayısını belirlemektir. Örneğin, 9 öğe 3x3 kareye sığar. 10 öğe için 4x4 kare gerekir. Ancak, alan kazanmak için genellikle başlangıç karesinin bir satırını veya sütununu kaldırırken öğeleri sığdırabilirsiniz. Count=10 örneğinde, 4x3 veya 3x4 dikdörtgene sığar.
Panelin neden 10 öğe için 5x2 seçmediğini merak edebilirsiniz çünkü bu, öğe numarasına düzgün bir şekilde uyar. Ancak pratikte paneller, nadiren belirgin bir en boy oranına sahip dikdörtgenler olarak boyutlandırılır. En küçük kareler tekniği, boyutlandırma mantığını tipik düzen şekilleriyle iyi çalışacak şekilde ayarlamak ve hücre şekillerinin alışılmadık en boy oranları almasını teşvik etmemek için bir yöntemdir.
İlgili konular
Referans
Kavramlar
Windows developer