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

WPF/C#中如何为动态生成的自定义控件添加点击事件并访问其元素?

解决方案

方案1:自定义控件暴露公开事件(推荐,符合封装规范)

这是最优方案,控件内部只负责触发UI交互信号,业务逻辑完全交给外部实现,耦合度最低。

  1. 修改FixerBox自定义控件代码,新增公开事件并触发:
public partial class FixerBox : UserControl
{
    // 新增公开点击事件,外部直接绑定这个事件即可
    public event EventHandler SwitchClicked;

    // 原有属性、构造函数、btnOn/btnOff方法保持不变...

    private void FixBtnBk_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        // 触发外部绑定的事件,sender传递当前FixerBox实例,方便外部区分不同控件
        SwitchClicked?.Invoke(this, EventArgs.Empty);
        e.Handled = true;
    }

    private void FixBtnDot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        FixBtnBk_MouseLeftButtonDown(sender, e);
    }
}
  1. 主窗口绑定事件时直接绑定该公开事件即可,不需要访问控件内部元素:
public MainWindow()
{
    InitializeComponent();
    var fixNames = fixers.FixerNames();
    foreach (string key in fixNames)
    {
        var temp = fixers.GetFix(key);
        temp["Name"] = key;
        fixerBoxes[key] = new FixerBox(temp);
        // 直接绑定公开事件
        fixerBoxes[key].SwitchClicked += fixClick;
        FixersArea.Children.Add(fixerBoxes[key]);
    }           
}

你的fixClick方法不需要做任何修改,直接就能正常使用。


方案2:强制转换内部元素类型(不推荐,依赖内部UI结构)

你原来的代码报错是因为FindName返回的是object类型,需要显式转换为对应的UI元素类型才能访问事件:

public MainWindow()
{
    InitializeComponent();
    var fixNames = fixers.FixerNames();
    foreach (string key in fixNames)
    {
        var temp = fixers.GetFix(key);
        temp["Name"] = key;
        fixerBoxes[key] = new FixerBox(temp);
        
        // 转换为实际的元素类型,这里假设FixBtnBk是Rectangle,FixBtnDot是Ellipse
        var btnBk = fixerBoxes[key].FindName("FixBtnBk") as System.Windows.Shapes.Rectangle;
        var btnDot = fixerBoxes[key].FindName("FixBtnDot") as System.Windows.Shapes.Ellipse;
        if (btnBk != null) btnBk.MouseLeftButtonDown += fixClick;
        if (btnDot != null) btnDot.MouseLeftButtonDown += fixClick;
        
        FixersArea.Children.Add(fixerBoxes[key]);
    }           
}

注意需要同步修改fixClick的参数和逻辑适配路由事件:

private void fixClick(object sender, MouseButtonEventArgs e)
{
    StatusBox.Text = "CLICK WORKS";
    // 从事件源的父级找到FixerBox实例
    FixerBox whichFix = (FixerBox)((FrameworkElement)sender).TemplatedParent;
    if (whichFix.IsOn)
    {
        whichFix.btnOff();
    }
    else
    {
        whichFix.btnOn();
    }
}

该方案缺点是如果后续你修改了控件内部的元素名称、类型,外部绑定代码会全部失效,维护成本更高。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 02:15:05