Bagikan melalui


Automasi UI dari Kontrol Kustom WPF

Automasi UI menyediakan satu antarmuka umum yang dapat digunakan klien otomatisasi untuk memeriksa atau mengoperasikan antarmuka pengguna dari berbagai platform dan kerangka kerja. Automasi UI memungkinkan kode jaminan kualitas (pengujian) dan aplikasi aksesibilitas seperti pembaca layar untuk memeriksa elemen antarmuka pengguna dan mensimulasikan interaksi pengguna dengan mereka dari kode lain. Untuk informasi tentang Automasi UI di semua platform, lihat Aksesibilitas.

Topik ini menjelaskan cara mengimplementasikan penyedia Automation UI sisi server untuk kontrol kustom yang berjalan dalam aplikasi WPF. WPF mendukung Automasi UI melalui pohon objek otomatisasi serekan yang menyejajarkan pohon elemen antarmuka pengguna. Kode pengujian dan aplikasi yang menyediakan fitur aksesibilitas dapat menggunakan objek peer otomatisasi secara langsung (untuk kode dalam proses) atau melalui antarmuka umum yang disediakan oleh UI Automation.

Kelas Peer Automation

Kontrol WPF mendukung Automasi UI melalui pohon kelas serekan yang berasal dari AutomationPeer. Menurut konvensi, nama kelas serekan dimulai dengan nama kelas kontrol dan diakhpuni dengan "AutomationPeer". Misalnya, ButtonAutomationPeer adalah kelas serekan Button untuk kelas kontrol. Kelas serekan kira-kira setara dengan jenis kontrol Automation UI tetapi khusus untuk elemen WPF. Kode automasi yang mengakses aplikasi WPF melalui antarmuka Automation UI tidak menggunakan rekan otomatisasi secara langsung, tetapi kode otomatisasi di ruang proses yang sama dapat menggunakan rekan otomatisasi secara langsung.

Kelas Peer Automation Bawaan

Elemen menerapkan kelas peer otomatisasi jika mereka menerima aktivitas antarmuka dari pengguna, atau jika berisi informasi yang diperlukan oleh pengguna aplikasi pembaca layar. Tidak semua elemen visual WPF memiliki rekan otomatisasi. Contoh kelas yang menerapkan rekan otomatisasi adalah Button, , TextBoxdan Label. Contoh kelas yang tidak menerapkan rekan otomatisasi adalah kelas yang berasal dari Decorator, seperti Border, dan kelas berdasarkan Panel, seperti Grid dan Canvas.

Kelas dasar Control tidak memiliki kelas serekan yang sesuai. Jika Anda memerlukan kelas serekan yang sesuai dengan kontrol kustom yang berasal dari Control, Anda harus memperoleh kelas serekan kustom dari FrameworkElementAutomationPeer.

Pertimbangan Keamanan untuk Serekan Turunan

Rekan automasi harus berjalan di lingkungan kepercayaan parsial. Kode dalam rakitan UIAutomationClient tidak dikonfigurasi untuk berjalan di lingkungan kepercayaan parsial, dan kode serekan otomatisasi tidak boleh mereferensikan perakitan tersebut. Sebagai gantinya, Anda harus menggunakan kelas di rakitan UIAutomationTypes. Misalnya, Anda harus menggunakan AutomationElementIdentifiers kelas dari rakitan UIAutomationTypes, yang sesuai dengan AutomationElement kelas di rakitan UIAutomationClient. Aman untuk mereferensikan rakitan UIAutomationTypes dalam kode serekan otomatisasi.

Navigasi Serekan

Setelah menemukan serekan otomatisasi, kode dalam proses dapat menavigasi pohon serekan dengan memanggil metode dan GetParent objekGetChildren. Navigasi di antara elemen WPF dalam kontrol didukung oleh implementasi metode serekan GetChildrenCore . Sistem Automasi UI memanggil metode ini untuk membangun pohon subelemen yang terkandung dalam kontrol; misalnya, mencantumkan item dalam kotak daftar. Metode default UIElementAutomationPeer.GetChildrenCore melintasi pohon visual elemen untuk membangun pohon rekan otomatisasi. Kontrol kustom mengambil alih metode ini untuk mengekspos elemen turunan ke klien otomatisasi, mengembalikan serekan otomatisasi elemen yang menyampaikan informasi atau mengizinkan interaksi pengguna.

Kustomisasi dalam Serekan Turunan

Semua kelas yang berasal dari UIElement dan ContentElement berisi metode OnCreateAutomationPeervirtual yang dilindungi . WPF memanggil OnCreateAutomationPeer untuk mendapatkan objek peer otomatisasi untuk setiap kontrol. Kode automasi dapat menggunakan serekan untuk mendapatkan informasi tentang karakteristik dan fitur kontrol dan untuk mensimulasikan penggunaan interaktif. Kontrol kustom yang mendukung otomatisasi harus mengambil alih OnCreateAutomationPeer dan mengembalikan instans kelas yang berasal dari AutomationPeer. Misalnya, jika kontrol kustom berasal dari ButtonBase kelas , maka objek yang dikembalikan oleh OnCreateAutomationPeer harus berasal dari ButtonBaseAutomationPeer.

Saat menerapkan kontrol kustom, Anda harus mengambil alih metode "Core" dari kelas peer otomatisasi dasar yang menggambarkan perilaku unik dan khusus untuk kontrol kustom Anda.

Mengambil alih OnCreateAutomationPeer

Ambil alih OnCreateAutomationPeer metode untuk kontrol kustom Anda sehingga mengembalikan objek penyedia Anda, yang harus berasal secara langsung atau tidak langsung dari AutomationPeer.

Mengambil alih GetPattern

Peer Automation menyederhanakan beberapa aspek implementasi penyedia Automation UI sisi server, tetapi rekan otomatisasi kontrol kustom masih harus menangani antarmuka pola. Seperti penyedia non-WPF, serekan mendukung pola kontrol dengan menyediakan implementasi antarmuka di System.Windows.Automation.Provider namespace layanan, seperti IInvokeProvider. Antarmuka pola kontrol dapat diimplementasikan oleh rekan itu sendiri atau oleh objek lain. Implementasi serekan GetPattern mengembalikan objek yang mendukung pola yang ditentukan. Kode Automasi UI memanggil GetPattern metode dan menentukan PatternInterface nilai enumerasi. Penimpaan GetPattern Anda harus mengembalikan objek yang mengimplementasikan pola yang ditentukan. Jika kontrol Anda tidak memiliki implementasi kustom pola, Anda dapat memanggil implementasi GetPattern jenis dasar untuk mengambil implementasinya atau null jika pola tidak didukung untuk jenis kontrol ini. Misalnya, kontrol NumericUpDown kustom dapat diatur ke nilai dalam rentang, sehingga peer Automation UI-nya akan mengimplementasikan IRangeValueProvider antarmuka. Contoh berikut menunjukkan bagaimana metode peer GetPattern ditimpa untuk merespons PatternInterface.RangeValue nilai.

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

Metode GetPattern juga dapat menentukan subelemen sebagai penyedia pola. Kode berikut menunjukkan cara ItemsControl mentransfer penanganan pola gulir ke serekan kontrol internalnya ScrollViewer .

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  

Untuk menentukan subelemen untuk penanganan pola, kode ini mendapatkan objek subelement, membuat serekan dengan menggunakan CreatePeerForElement metode , mengatur EventsSource properti peer baru ke peer saat ini, dan mengembalikan peer baru. Pengaturan EventsSource pada subelemen mencegah subelemen muncul di pohon serekan otomatisasi dan menunjuk semua peristiwa yang dinaikkan oleh subelemen sebagai berasal dari kontrol yang ditentukan dalam EventsSource. ScrollViewer Kontrol tidak muncul di pohon otomatisasi, dan menggulir peristiwa yang dihasilkannya tampaknya berasal dari ItemsControl objek.

Mengambil alih Metode "Core"

Kode automasi mendapatkan informasi tentang kontrol Anda dengan memanggil metode publik kelas serekan. Untuk memberikan informasi tentang kontrol Anda, ambil alih setiap metode yang namanya berakhiran dengan "Core" ketika implementasi kontrol Anda berbeda dari yang disediakan oleh kelas peer otomatisasi dasar. Minimal, kontrol Anda harus menerapkan GetClassNameCore metode dan GetAutomationControlTypeCore , seperti yang ditunjukkan dalam contoh berikut.

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

Implementasi GetAutomationControlTypeCore Anda menjelaskan kontrol Anda dengan mengembalikan ControlType nilai. Meskipun Anda dapat mengembalikan ControlType.Custom, Anda harus mengembalikan salah satu jenis kontrol yang lebih spesifik jika secara akurat menjelaskan kontrol Anda. Nilai ControlType.Custom pengembalian memerlukan pekerjaan ekstra bagi penyedia untuk menerapkan Automasi UI, dan produk klien UI Automation tidak dapat mengantisipasi struktur kontrol, interaksi keyboard, dan pola kontrol yang mungkin.

Terapkan IsContentElementCore metode dan IsControlElementCore untuk menunjukkan apakah kontrol Anda berisi konten data atau memenuhi peran interaktif di antarmuka pengguna (atau keduanya). Secara default, kedua metode mengembalikan true. Pengaturan ini meningkatkan kegunaan alat otomatisasi seperti pembaca layar, yang dapat menggunakan metode ini untuk memfilter pohon otomatisasi. Jika metode Anda GetPattern mentransfer penanganan pola ke serekan subelemen, metode serekan IsControlElementCore subelemen dapat mengembalikan false untuk menyembunyikan serekan subelemen dari pohon otomatisasi. Misalnya, menggulir dalam ditangani oleh , dan peer otomatisasi untuk PatternInterface.Scroll dikembalikan oleh GetPattern metode ScrollViewerAutomationPeer yang terkait dengan ListBoxAutomationPeer.ScrollViewerListBox Oleh karena itu, IsControlElementCore metode ScrollViewerAutomationPeer pengembalian false, sehingga ScrollViewerAutomationPeer tidak muncul di pohon otomatisasi.

Peer otomatisasi Anda harus memberikan nilai default yang sesuai untuk kontrol Anda. Perhatikan bahwa XAML yang mereferensikan kontrol Anda dapat mengambil alih implementasi serekan metode inti Anda dengan menyertakan AutomationProperties atribut. Misalnya, XAML berikut membuat tombol yang memiliki dua properti Automation UI yang disesuaikan.

<Button AutomationProperties.Name="Special"
    AutomationProperties.HelpText="This is a special button."/>  

Menerapkan Penyedia Pola

Antarmuka yang diterapkan oleh penyedia kustom secara eksplisit dideklarasikan jika elemen pemilik berasal langsung dari Control. Misalnya, kode berikut mendeklarasikan serekan untuk Control yang mengimplementasikan nilai rentang.

public class RangePeer1 : FrameworkElementAutomationPeer, IRangeValueProvider { }  
Public Class RangePeer1  
    Inherits FrameworkElementAutomationPeer  
    Implements IRangeValueProvider  
End Class  

Jika kontrol pemilik berasal dari jenis kontrol tertentu seperti RangeBase, rekan dapat berasal dari kelas serekan turunan yang setara. Dalam hal ini, rekan akan berasal dari RangeBaseAutomationPeer, yang memasok implementasi IRangeValueProviderdasar . Kode berikut menunjukkan deklarasi serekan seperti itu.

public class RangePeer2 : RangeBaseAutomationPeer { }  
Public Class RangePeer2  
    Inherits RangeBaseAutomationPeer  
End Class  

Untuk contoh implementasi, lihat kode sumber C# atau Visual Basic yang mengimplementasikan dan menggunakan kontrol kustom NumericUpDown.

Naikkan Peristiwa

Klien Automation dapat berlangganan peristiwa otomatisasi. Kontrol kustom harus melaporkan perubahan ke status kontrol dengan memanggil RaiseAutomationEvent metode . Demikian pula, ketika nilai properti berubah, panggil RaisePropertyChangedEvent metode . Kode berikut menunjukkan cara mendapatkan objek serekan dari dalam kode kontrol dan memanggil metode untuk menaikkan peristiwa. Sebagai pengoptimalan, kode menentukan apakah ada pendengar untuk jenis peristiwa ini. Meningkatkan peristiwa hanya ketika ada pendengar menghindari overhead yang tidak perlu dan membantu kontrol tetap responsif.

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

Baca juga