Làm thế nào để lập trình bấm vào một nút trong WPF?


144

Vì không có button.PerformClick()phương pháp nào trong WPF, nên có cách nào để nhấp vào nút WPF theo chương trình không?

Câu trả lời:


128

WPF có một cách tiếp cận hơi khác so với WinForms ở đây. Thay vì tự động hóa một đối tượng được tích hợp trong API, họ có một lớp riêng cho từng đối tượng chịu trách nhiệm tự động hóa nó. Trong trường hợp này, bạn cần phải ButtonAutomationPeerhoàn thành nhiệm vụ này.

ButtonAutomationPeer peer = new ButtonAutomationPeer(someButton);
IInvokeProvider invokeProv = peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
invokeProv.Invoke();

Đây là một bài viết trên blog về chủ đề này.

Lưu ý: IInvokeProvidergiao diện được xác định trong UIAutomationProviderlắp ráp.


2
Slick, tôi đã không nhận thức được điều này. Có thể rất hữu ích cho thử nghiệm tự động. Lưu ý rằng có một nhận xét về liên kết đó gợi ý sử dụng một nhà máy được cung cấp để có được sự tự động hóa ngang hàng thay vì tự tạo một liên kết.
Greg D

7
Cảm ơn vì điều đó. Tôi đã vật lộn để tìm các không gian tên chính xác trong ứng dụng của mình, cho đến khi tôi thêm một tham chiếu đến UIAutomationProvider. Sau đó phải thêmusing System.Windows.Automation.Peers; using System.Windows.Automation.Provider;
trung

5
Một lót cho người nghiêng:((IInvokeProvider) (new ButtonAutomationPeer(someButton).GetPattern(PatternInterface.Invoke)).Invoke();
Daniel Beckett

3
Một điều cần lưu ý là cuộc gọi Gọi không đồng bộ. Điều đó có nghĩa là nếu bạn đang sử dụng nó trong một bài kiểm tra đơn vị và dòng tiếp theo của bạn là để kiểm tra kết quả mong đợi của việc nhấp vào nút, bạn có thể phải chờ.
chối

3
Chỉ để tham khảo, IInvokeProvidergiao diện được xác định trong UIAutomationProviderlắp ráp.
Steven Rands

188

Giống như JaredPar cho biết bạn có thể tham khảo bài viết của Josh Smith về Tự động hóa. Tuy nhiên, nếu bạn xem qua các bình luận cho bài viết của anh ấy, bạn sẽ thấy cách nâng cao sự kiện thanh lịch hơn đối với các điều khiển WPF

someButton.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));

Cá nhân tôi thích cái ở trên thay vì tự động hóa đồng nghiệp.


26
Giải pháp RaiseEvent chỉ làm tăng sự kiện. Nó không thực thi Lệnh được liên kết với Nút (như Skanaar nói)
Eduardo Molteni

4
Nếu bạn sử dụng XAML, ví dụ <Tên nút = "X" Click = "X_Click" />, sự kiện sẽ được xử lý bởi trình xử lý nhấp chuột như bình thường. +1 từ tôi!
metao

4
Tôi đang sử dụng VB ... không chắc mã có khác với các câu VB C # không, nhưng new RoutedEventArgs(Button.ClickEvent)không hoạt động với tôi. Tôi đã phải sử dụng new RoutedEventArgs(Primitives.ButtonBase.ClickEvent). Nếu không, làm việc tuyệt vời!
BrianVPS

3
Để giải thích chi tiết về @EduardoMolteni và Skanaar, bạn sẽ mất chức năng IsEnables được cung cấp bởi Lệnh theo cách này, vì vậy trừ khi bạn muốn tất cả các sự kiện của mình kiểm tra xem chúng có được bật hay không, AutomaticPeer hoạt động tốt hơn.
Justin Pihony

34

nếu bạn muốn gọi sự kiện bấm vào:

SomeButton.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));

Và nếu bạn muốn nút này trông giống như được nhấn:

typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(SomeButton, new object[] { true });

và không bị áp bức sau đó:

typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(SomeButton, new object[] { false });

hoặc sử dụng ToggleButton


22
this.PowerButton.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));

5

Một cách để lập trình "bấm" nút, nếu bạn có quyền truy cập vào nguồn, chỉ cần gọi trình xử lý sự kiện OnClick của nút (hoặc Thực thi ICommand được liên kết với nút, nếu bạn đang thực hiện theo cách WPF-y hơn ).

Tại sao anh làm điều này? Bạn đang thực hiện một số loại thử nghiệm tự động, ví dụ, hoặc cố gắng thực hiện cùng một hành động mà nút thực hiện từ một phần khác của mã?


Đó không phải là giải pháp duy nhất cho vấn đề của tôi, nhưng khi tôi thử làm điều này, tôi thấy rằng nó không dễ như nút.PerformClick (), vì vậy chỉ cần một chút tò mò ... :)
tghoang

Tôi đã phải bấm vào menu của một cửa sổ khác trong cùng dự án và MyOtherWindow.mnuEntry_Click (Tôi, Windows mới.RoutedEventArss) đã làm điều đó. Thực sự đơn giản.
Andrea Antonangeli

4

Như Greg D đã nói, tôi nghĩ rằng một cách khác để Automationnhấp vào nút bằng cách sử dụng mẫu MVVM (nhấp vào sự kiện được nêu và lệnh được thực thi) là gọi OnClickphương thức bằng phản xạ:

typeof(System.Windows.Controls.Primitives.ButtonBase).GetMethod("OnClick", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(button, new object[0]);

Đây là một cách tốt để sử dụng một sự kiện từ một phần tử con để bắn lệnh cho cha mẹ.
Cool Blue

2

Khi sử dụng mẫu Lệnh MVVM cho chức năng Nút (thực hành được khuyến nghị), một cách đơn giản để kích hoạt hiệu ứng của Nút như sau:

someButton.Command.Execute(someButton.CommandParameter);

Điều này sẽ sử dụng đối tượng Command mà nút kích hoạt và vượt qua CommandParameter được xác định bởi XAML .


Một lưu ý, điều này chỉ kích hoạt hiệu ứng mà nút sẽ có nếu được nhấp. Nó không tạo ra bất kỳ sự kiện nhấp chuột nào trong hàng đợi gửi tin nhắn. Đối với tất cả các trường hợp thực tế, đây là những gì bạn sẽ mong muốn và sẽ tránh các sự kiện điều phối không cần thiết (ví dụ như nhiều người thực hiện hơn) nhưng nếu bạn thực sự yêu cầu các sự kiện điều phối thì các giải pháp khác ở trên phù hợp hơn
KVKConsultancy

0

Vấn đề với giải pháp API tự động hóa là, nó yêu cầu tham chiếu đến khung công tác UIAutomationProviderdưới dạng phụ thuộc dự án / gói.

Một cách khác là mô phỏng hành vi. Trong phần sau đây có giải pháp mở rộng của tôi, nó cũng điều khiển mẫu MVVM với các lệnh bị ràng buộc của nó - được triển khai như phương thức mở rộng :

public static class ButtonExtensions
{
    /// <summary>
    /// Performs a click on the button.<br/>
    /// This is the WPF-equivalent of the Windows Forms method "<see cref="M:System.Windows.Forms.Button.PerformClick" />".
    /// <para>This simulates the same behaviours as the button was clicked by the user by keyboard or mouse:<br />
    /// 1. The raising the ClickEvent.<br />
    /// 2.1. Checking that the bound command can be executed, calling <see cref="ICommand.CanExecute" />, if a command is bound.<br />
    /// 2.2. If command can be executed, then the <see cref="ICommand.Execute(object)" /> will be called and the optional bound parameter is p
    /// </para>
    /// </summary>
    /// <param name="sourceButton">The source button.</param>
    /// <exception cref="ArgumentNullException">sourceButton</exception>
    public static void PerformClick(this Button sourceButton)
    {
        // Check parameters
        if (sourceButton == null)
            throw new ArgumentNullException(nameof(sourceButton));

        // 1.) Raise the Click-event
        sourceButton.RaiseEvent(new RoutedEventArgs(System.Windows.Controls.Primitives.ButtonBase.ClickEvent));

        // 2.) Execute the command, if bound and can be executed
        ICommand boundCommand = sourceButton.Command;
        if (boundCommand != null)
        {
            object parameter = sourceButton.CommandParameter;
            if (boundCommand.CanExecute(parameter) == true)
                boundCommand.Execute(parameter);
        }
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.