WPF Özel Denetiminin Kullanıcı Arayüzü Otomatikleştirilmesi
UI Otomasyonu, otomasyon istemcilerinin çeşitli platformların ve çerçevelerin kullanıcı arabirimlerini incelemek veya çalıştırmak için kullanabileceği tek, genelleştirilmiş bir arabirim sağlar. UI Otomasyonu, hem kalite güvencesi (test) koduna hem de ekran okuyucular gibi erişilebilirlik uygulamalarının kullanıcı arabirimi öğelerini incelemesine ve diğer kodlardan kullanıcı etkileşimi simülasyonu yapmalarına olanak tanır. Tüm platformlarda UI Otomasyonu hakkında bilgi için bkz. Erişilebilirlik.
Bu konu başlığında, WPF uygulamasında çalışan özel bir denetim için sunucu tarafı UI Otomasyonu sağlayıcısının nasıl uygulandığı açıklanmaktadır. WPF, kullanıcı arabirimi öğelerinin ağacını paralel hale getiren eş otomasyon nesneleri ağacı aracılığıyla UI Otomasyonunu destekler. Test kodu ve erişilebilirlik özellikleri sağlayan uygulamalar, otomasyon eş nesnelerini doğrudan (işlem içi kod için) veya UI Otomasyonu tarafından sağlanan genelleştirilmiş arabirim aracılığıyla kullanabilir.
Otomasyon Eş Sınıfları
WPF denetimleri, AutomationPeertüretilen eş sınıflardan oluşan bir ağaç üzerinden UI Automation'ı destekler. Kural gereği, eş sınıf adları denetim sınıfı adıyla başlar ve "AutomationPeer" ile biter. Örneğin, ButtonAutomationPeerButton denetim sınıfının eş sınıfıdır. Eş sınıfları kabaca UI Otomasyonu denetim türlerine eşdeğerdir, ancak WPF öğelerine özeldir. UI Otomasyonu arabirimi aracılığıyla WPF uygulamalarına erişen otomasyon kodu doğrudan otomasyon eşlerini kullanmaz, ancak aynı işlem alanında otomasyon kodu otomasyon eşlerini doğrudan kullanabilir.
Yerleşik Otomasyon Eş Sınıfları
Öğeler, kullanıcıdan arabirim etkinliğini kabul ederse veya ekran okuyucu uygulamalarının kullanıcıları tarafından gereken bilgileri içeriyorsa bir otomasyon eş sınıfı uygular. Tüm WPF görsel öğelerinin otomasyon eşleri yoktur. Otomasyon eşlerini uygulayan sınıflara örnek olarak Button, TextBoxve Labelverilebilir. Otomasyon eşlerini uygulamayan sınıflara örnek olarak, Bordergibi Decoratortüretilen sınıflar ve Grid ve Canvasgibi Paneltabanlı sınıflar verilebilir.
Temel Control sınıfının karşılık gelen bir eş sınıfı yoktur. Control'den türetilen özel bir denetime karşılık gelen bir eş sınıfına ihtiyacınız varsa, özel eş sınıfını FrameworkElementAutomationPeer'den türetmelisiniz.
Türetilmiş Eşler İçin Güvenlikle İlgili Dikkat Edilmesi Gereken Hususlar
Otomasyon birimleri kısmi güven ortamında çalışmalıdır. UIAutomationClient derlemesindeki kod, kısmi güven ortamında çalışacak şekilde yapılandırılmadı ve otomasyon eş kodu bu derlemeye başvurmamalıdır. Bunun yerine, UIAutomationTypes derlemesindeki sınıfları kullanmanız gerekir. Örneğin, UIAutomationClient derlemesindeki AutomationElement sınıfına karşılık gelen UIAutomationTypes derlemesindeki AutomationElementIdentifiers sınıfını kullanmanız gerekir. Otomasyon eş kodunda UIAutomationTypes derlemesine başvurmak güvenlidir.
Akran Rehberliği
Otomasyon eşleri bulunduktan sonra işlem içi kod, nesnenin GetChildren ve GetParent yöntemlerini çağırarak eş ağaçta gezinebilir. Denetim içindeki WPF öğeleri arasında gezinme, benzerin GetChildrenCore yöntemini uygulamasıyla desteklenir. UI Otomasyonu sistemi, bir denetimin içinde yer alan alt öğelerden oluşan bir ağaç oluşturmak için bu yöntemi çağırır; örneğin, liste kutusundaki liste öğeleri. Varsayılan UIElementAutomationPeer.GetChildrenCore yöntemi, otomasyon eşlerinin ağacını oluşturmak için öğelerin görsel ağacından geçiş yapar. Özel denetimler, bilgileri aktaran veya kullanıcı etkileşimine izin veren öğelerin otomasyon eşlerini döndürerek alt öğeleri otomasyon istemcilerine göstermek için bu yöntemi geçersiz kılar.
Türev Eşteki Özelleştirmeler
UIElement ve ContentElement’den türetilen sınıfların tümü, OnCreateAutomationPeerkorumalı sanal yöntemini içerir. WPF, her denetim için otomasyon eş nesnesini almak için OnCreateAutomationPeer çağırır. Otomasyon kodu, bir denetimin özellikleri ve nitelikleri hakkında bilgi toplamak ve etkileşimli kullanımın benzetimini yapmak için eş nesneyi kullanabilir. Otomasyonu destekleyen özel bir denetim OnCreateAutomationPeer geçersiz kılmalı ve AutomationPeertüretilen bir sınıfın örneğini döndürmelidir. Örneğin, özel bir denetim ButtonBase sınıfından türetilirse, OnCreateAutomationPeer tarafından döndürülen nesne ButtonBaseAutomationPeer'den türetilmelidir.
Özel denetim uygularken, temel otomasyon eş sınıfından benzersiz ve özel denetiminize özgü davranışı açıklayan "Core" yöntemlerini geçersiz kılmanız gerekir.
OnCreateAutomationPeer'ı Geçersiz Kıl
Doğrudan veya dolaylı olarak AutomationPeertüretmesi gereken sağlayıcı nesnenizi döndürmesi için özel denetiminiz için OnCreateAutomationPeer yöntemini geçersiz kılın.
GetPattern'ı Geçersiz Kıl
Otomasyon eşleri, sunucu tarafı UI Otomasyonu sağlayıcılarının bazı uygulama yönlerini basitleştirir, ancak özel denetim otomasyonu eşlerinin yine de desen arabirimlerini işlemesi gerekir. WPF olmayan sağlayıcılar gibi eşler de System.Windows.Automation.Provider ad alanında IInvokeProvidergibi arabirimlerin uygulamalarını sağlayarak denetim desenlerini destekler. Denetim deseni arabirimleri eş tarafından veya başka bir nesne tarafından uygulanabilir. Eşlerin GetPattern uygulaması, belirtilen deseni destekleyen nesneyi döndürür. UI Otomasyonu kodu GetPattern yöntemini çağırır ve bir PatternInterface numaralandırma değeri belirtir. GetPattern geçersiz kılma işleminiz, belirtilen deseni uygulayan nesneyi döndürmelidir. Denetiminiz özel bir desen uygulamasına sahip değilse, temel türün GetPattern uygulamasını çağırmak suretiyle onun uygulamasını veya eğer bu denetim türü için desen desteklenmiyorsa null değerini alabilirsiniz. Örneğin, özel bir NumericUpDown denetimi bir aralık içindeki bir değere ayarlanabilir, bu nedenle UI Otomasyonu eşi IRangeValueProvider arabirimini uygular. Aşağıdaki örnek, eşin GetPattern yönteminin bir PatternInterface.RangeValue değerine yanıt vermek üzere nasıl geçersiz kılındığını göstermektedir.
public override object GetPattern(PatternInterface patternInterface)
{
if (patternInterface == PatternInterface.RangeValue)
{
return this;
}
return base.GetPattern(patternInterface);
}
Public Overrides Function GetPattern(ByVal patternInterface As PatternInterface) As Object
If patternInterface = PatternInterface.RangeValue Then
Return Me
End If
Return MyBase.GetPattern(patternInterface)
End Function
GetPattern yöntemi, desen sağlayıcısı olarak bir alt öğe de belirtebilir. Aşağıdaki kod, ItemsControl kaydırma deseni işlemesini dahilî ScrollViewer denetiminin eşine nasıl aktardığını gösterir.
public override object GetPattern(PatternInterface patternInterface)
{
if (patternInterface == PatternInterface.Scroll)
{
ItemsControl owner = (ItemsControl) base.Owner;
// ScrollHost is internal to the ItemsControl class
if (owner.ScrollHost != null)
{
AutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement(owner.ScrollHost);
if ((peer != null) && (peer is IScrollProvider))
{
peer.EventsSource = this;
return (IScrollProvider) peer;
}
}
}
return base.GetPattern(patternInterface);
}
Public Class Class1
Public Overrides Function GetPattern(ByVal patternInterface__1 As PatternInterface) As Object
If patternInterface1 = PatternInterface.Scroll Then
Dim owner As ItemsControl = DirectCast(MyBase.Owner, ItemsControl)
' ScrollHost is internal to the ItemsControl class
If owner.ScrollHost IsNot Nothing Then
Dim peer As AutomationPeer = UIElementAutomationPeer.CreatePeerForElement(owner.ScrollHost)
If (peer IsNot Nothing) AndAlso (TypeOf peer Is IScrollProvider) Then
peer.EventsSource = Me
Return DirectCast(peer, IScrollProvider)
End If
End If
End If
Return MyBase.GetPattern(patternInterface1)
End Function
End Class
Desen işleme için bir alt öğe belirtmek için, bu kod alt öğe nesnesini alır, CreatePeerForElement yöntemini kullanarak bir eş oluşturur, yeni eşlerin EventsSource özelliğini geçerli eşe ayarlar ve yeni eş değerini döndürür. Bir alt öğede EventsSource ayarı, alt öğesinin otomasyon eş ağacında görünmesini engeller ve alt öğesi tarafından EventsSourceiçinde belirtilen denetimden kaynaklanan olarak tetiklenen tüm olayları belirler. ScrollViewer denetimi otomasyon ağacında görünmez ve oluşturduğu kaydırma olayları ItemsControl nesnesinden geliyor gibi görünür.
"Core" Yöntemlerini Geçersiz Kılma
Otomasyon kodu, eş sınıfının genel yöntemlerini çağırarak denetiminiz hakkında bilgi alır. Denetiminiz hakkında bilgi sağlamak için, denetim uygulamanız temel otomasyon eş sınıfı tarafından sağlanandan farklı olduğunda adı "Core" ile biten her yöntemi geçersiz kılın. Aşağıdaki örnekte gösterildiği gibi, denetiminizin en azından GetClassNameCore ve GetAutomationControlTypeCore yöntemlerini uygulaması gerekir.
protected override string GetClassNameCore()
{
return "NumericUpDown";
}
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Spinner;
}
Protected Overrides Function GetClassNameCore() As String
Return "NumericUpDown"
End Function
Protected Overrides Function GetAutomationControlTypeCore() As AutomationControlType
Return AutomationControlType.Spinner
End Function
GetAutomationControlTypeCore uygulamanız, ControlType değeri döndürerek kontrol mekanizmanızı tanımlar. ControlType.Customdöndürebilmenize rağmen, denetiminizi doğru şekilde açıklıyorsa daha belirli denetim türlerinden birini döndürmelisiniz. ControlType.Custom dönüş değeri, sağlayıcının UI Otomasyonu uygulaması için ek çalışma gerektirir ve UI Otomasyonu istemci ürünleri denetim yapısını, klavye etkileşimini ve olası denetim desenlerini tahmin edemez.
Denetiminizin veri içeriği içerip içermediğini veya kullanıcı arabiriminde (veya her ikisinde) etkileşimli bir rolü yerine getirip getirmediğini belirtmek için IsContentElementCore ve IsControlElementCore yöntemlerini uygulayın. Varsayılan olarak, her iki yöntem de true
döndürür. Bu ayarlar, otomasyon ağacını filtrelemek için bu yöntemleri kullanabilen ekran okuyucular gibi otomasyon araçlarının kullanılabilirliğini artırır.
GetPattern yönteminiz desen işlemeyi bir alt öğe eşine aktarırsa, alt öğe eş öğesinin IsControlElementCore yöntemi, alt öğe eşlerini otomasyon ağacından gizlemek için false döndürebilir. Örneğin, bir ListBox kaydırma işlemi bir ScrollViewertarafından işlenir ve PatternInterface.Scroll için otomasyon eş değeri, ListBoxAutomationPeerile ilişkili ScrollViewerAutomationPeerGetPattern yöntemi tarafından döndürülür. Bu nedenle, ScrollViewerAutomationPeerIsControlElementCore yöntemi false
döndürür, böylece ScrollViewerAutomationPeer otomasyon ağacında görünmez.
Otomasyon eşinizin denetiminiz için uygun varsayılan değerleri sağlaması gerekir. Denetiminize başvuran XAML'nin, AutomationProperties öznitelikleri ekleyerek temel yöntemlerin eş uygulamalarınızı geçersiz kılabileceğini unutmayın. Örneğin, aşağıdaki XAML iki özelleştirilmiş UI Otomasyonu özelliğine sahip bir düğme oluşturur.
<Button AutomationProperties.Name="Special"
AutomationProperties.HelpText="This is a special button."/>
Desen Sağlayıcılarını Uygulama
Özel bir sağlayıcı tarafından uygulanan arabirimler, sahibi olan öğe doğrudan Control'dan türetiliyorsa açıkça bildirilir. Örneğin, aşağıdaki kod bir aralık değeri uygulayan bir Control için bir eş tanımlar.
public class RangePeer1 : FrameworkElementAutomationPeer, IRangeValueProvider { }
Public Class RangePeer1
Inherits FrameworkElementAutomationPeer
Implements IRangeValueProvider
End Class
Sahip olan kontrol RangeBasegibi belirli bir denetim türünden türetilirse, bu denetimle eşdeğer türetilmiş bir eş sınıfından türetilebilir. Bu durumda, eş, IRangeValueProvideriçin bir temel uygulama sağlayan RangeBaseAutomationPeer'dan türetilir. Aşağıdaki kod, böyle bir eş bildirimini gösterir.
public class RangePeer2 : RangeBaseAutomationPeer { }
Public Class RangePeer2
Inherits RangeBaseAutomationPeer
End Class
Örnek bir uygulama için, NumericUpDown özel denetimini uygulayan ve kullanan C# veya Visual Basic kaynak koduna bakın.
Olayları Tetikle
Otomasyon istemcileri otomasyon olaylarına abone olabilir. Özel denetimlerin, RaiseAutomationEvent yöntemini çağırarak denetim durumundaki değişiklikleri bildirmesi gerekir. Benzer şekilde, bir özellik değeri değiştiğinde RaisePropertyChangedEvent yöntemini çağırın. Aşağıdaki kod, denetim kodunun içinden eş nesnesinin nasıl elde edileceğini ve bir olayı tetiklemek için bir yöntemin nasıl çağrılacağını gösterir. İyileştirme olarak kod, bu olay türü için dinleyici olup olmadığını belirler. Olayın yalnızca dinleyiciler olduğunda yükseltilmesi gereksiz ek yükü önler ve denetimin yanıt vermeye devam etmesine yardımcı olur.
if (AutomationPeer.ListenerExists(AutomationEvents.PropertyChanged))
{
NumericUpDownAutomationPeer peer =
UIElementAutomationPeer.FromElement(nudCtrl) as NumericUpDownAutomationPeer;
if (peer != null)
{
peer.RaisePropertyChangedEvent(
RangeValuePatternIdentifiers.ValueProperty,
(double)oldValue,
(double)newValue);
}
}
If AutomationPeer.ListenerExists(AutomationEvents.PropertyChanged) Then
Dim peer As NumericUpDownAutomationPeer = TryCast(UIElementAutomationPeer.FromElement(nudCtrl), NumericUpDownAutomationPeer)
If peer IsNot Nothing Then
peer.RaisePropertyChangedEvent(RangeValuePatternIdentifiers.ValueProperty, CDbl(oldValue), CDbl(newValue))
End If
End If
Ayrıca bkz.
- UI Otomasyonuna Genel Bakış
- Server-Side UI Otomasyon Sağlayıcısı Uygulaması
- GitHub'da NumericUpDown özel denetimi (C#)
- NumericUpDown özel denetimi (Visual Basic), GitHub'da
.NET Desktop feedback