You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用TestStack.White测试WPF自定义UserControl的事件触发?

Hey Marco, I’ve tackled similar scenarios with TestStack.White and DevExpress WPF controls before, so let me walk you through a few solid approaches to verify those Loaded/Unloaded events fire correctly.

Approach 1: Add Test-Friendly Flags to Your Custom UserControl

This is the most straightforward method—extend your custom DevExpress UserControl with public flags that get updated when the target events trigger. You can then check these flags directly in your tests.

  • First, update your custom UserControl class to track event triggers:
public class CustomDevExpressUserControl : DevExpress.Xpf.LayoutControl.LayoutControl
{
    // Public flags to track event state
    public bool LoadedEventTriggered { get; private set; }
    public bool UnloadedEventTriggered { get; private set; }

    public CustomDevExpressUserControl()
    {
        // Subscribe to the events and update flags
        Loaded += (sender, e) => LoadedEventTriggered = true;
        Unloaded += (sender, e) => UnloadedEventTriggered = true;
    }
}
  • Then, in your TestStack.White test, retrieve the control and validate the flags after triggering load/unload actions:
// Assume you've already obtained the parent window instance
var targetControl = window.Get<CustomDevExpressUserControl>(SearchCriteria.ByAutomationId("MyControlAutomationId"));

// Trigger control loading (ensure it's rendered in the visual tree)
window.UpdateLayout();

// Verify Loaded event fired
Assert.IsTrue(targetControl.LoadedEventTriggered);

// Trigger control unloading (e.g., close the parent window or remove the control)
window.Close();

// Verify Unloaded event fired
Assert.IsTrue(targetControl.UnloadedEventTriggered);
Approach 2: Listen to UI Automation Events

TestStack.White is built on top of Windows UI Automation, so you can subscribe to automation-level events that correspond to WPF’s Loaded/Unloaded lifecycle.

  • Use automation event handlers to track when the control is added/removed from the visual tree:
var controlElement = targetControl.AutomationElement;
bool loadedFired = false;
bool unloadedFired = false;

// Subscribe to StructureChanged event to detect when the control is loaded
Automation.AddStructureChangedEventHandler(
    controlElement,
    TreeScope.Element,
    (sender, e) =>
    {
        if (e.StructureChangeType == StructureChangeType.ChildAdded)
        {
            loadedFired = true;
        }
    });

// Subscribe to WindowClosed event to detect when the control is unloaded
Automation.AddAutomationEventHandler(
    WindowPattern.WindowClosedEvent,
    controlElement,
    TreeScope.Element,
    (sender, e) =>
    {
        unloadedFired = true;
    });

// Trigger load action
window.UpdateLayout();
Assert.IsTrue(loadedFired);

// Trigger unload action
window.Close();
Assert.IsTrue(unloadedFired);

// Clean up event handlers to avoid memory leaks
Automation.RemoveStructureChangedEventHandler(controlElement, ...);
Automation.RemoveAutomationEventHandler(WindowPattern.WindowClosedEvent, controlElement, ...);
Approach 3: Bind Events to ViewModel Commands (If Using MVVM)

If your UserControl follows the MVVM pattern, you can bind the Loaded/Unloaded events to commands in your view model, then validate the view model’s state in tests.

  • In your UserControl’s XAML, bind the events to view model commands:
<UserControl 
    xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol"
    Loaded="{Binding OnControlLoadedCommand}" 
    Unloaded="{Binding OnControlUnloadedCommand}">
    <!-- Your control content here -->
</UserControl>
  • Update your view model to track command execution:
public class MyControlViewModel : DevExpress.Mvvm.ViewModelBase
{
    public bool LoadedCommandExecuted { get; private set; }
    public bool UnloadedCommandExecuted { get; private set; }

    public ICommand OnControlLoadedCommand => new DevExpress.Mvvm.DelegateCommand(() => 
        LoadedCommandExecuted = true);

    public ICommand OnControlUnloadedCommand => new DevExpress.Mvvm.DelegateCommand(() => 
        UnloadedCommandExecuted = true);
}
  • In your test, access the view model and validate the flags:
var viewModel = targetControl.DataContext as MyControlViewModel;
Assert.IsNotNull(viewModel);

// After triggering load
Assert.IsTrue(viewModel.LoadedCommandExecuted);

// After triggering unload
Assert.IsTrue(viewModel.UnloadedCommandExecuted);

内容的提问来源于stack exchange,提问作者Marco Moscato

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:08:08