如何通过PictureBox获取其所属的用户控件(UserControl)
这有几个靠谱的方案,都能帮你实现点击PictureBox时获取所属的UserControl实例,挑适合你的来用:
Parent属性直接获取(最简单直接) 因为你把PictureBox放在UserControl里,它的Parent属性默认就是这个UserControl(哪怕你不写pictureBox1.Parent = this也一样,拖进UserControl的控件默认父容器就是它)。所以在点击事件里,只需要把sender转成PictureBox,再取它的Parent就行:
private void item_click(object sender, EventArgs e) { // 将触发事件的控件转成PictureBox PictureBox clickedPictureBox = sender as PictureBox; if (clickedPictureBox != null) { // 获取对应的UserControl1实例 UserControl1 targetUC = clickedPictureBox.Parent as UserControl1; if (targetUC != null) { // 这里就可以操作这个UserControl实例了,比如打印它的名称 MessageBox.Show($"点击了UserControl:{targetUC.Name}"); } } }
注意:如果后续你给PictureBox套了其他容器(比如Panel),那Parent就会变成Panel,这时候可以递归向上找UserControl,或者用方案2更稳妥。
直接暴露UserControl内部的PictureBox给Form其实不太符合面向对象的封装思想,最好是让UserControl自己处理内部点击,然后对外暴露一个自定义事件,把自身实例传出去:
首先修改UserControl1的代码:
public partial class UserControl1 : UserControl { // 定义自定义事件,用来通知外部点击事件 public event EventHandler<UserControlClickedArgs> UserControlClicked; public UserControl1() { InitializeComponent(); // 内部给PictureBox绑定点击逻辑 pictureBox1.Click += OnPictureBoxClicked; } private void OnPictureBoxClicked(object sender, EventArgs e) { // 触发自定义事件,把当前UserControl实例作为参数传递 UserControlClicked?.Invoke(this, new UserControlClickedArgs(this)); } } // 自定义事件参数类,用来携带UserControl实例 public class UserControlClickedArgs : EventArgs { public UserControl1 TargetUserControl { get; } public UserControlClickedArgs(UserControl1 control) { TargetUserControl = control; } }
然后在Form里,你只需要绑定UserControl的自定义事件,不用管内部的PictureBox:
private void form1_Load(object sender, EventArgs e) { // 创建第一个UserControl var uc1 = new UserControl1(); uc1.Name = "UC_01"; uc1.UserControlClicked += OnUserControlClicked; this.Controls.Add(uc1); uc1.Location = new Point(20, 20); // 创建第二个UserControl var uc2 = new UserControl1(); uc2.Name = "UC_02"; uc2.UserControlClicked += OnUserControlClicked; this.Controls.Add(uc2); uc2.Location = new Point(20, 120); } private void OnUserControlClicked(object sender, UserControlClickedArgs e) { // 直接拿到点击的UserControl实例 UserControl1 clickedUC = e.TargetUserControl; MessageBox.Show($"点击了UserControl:{clickedUC.Name}"); }
这个方案的好处是,哪怕你以后修改UserControl内部的布局(比如把PictureBox换成Button),Form里的代码完全不用改,非常适合长期维护的项目。
Tag属性传递实例 如果觉得前面的方案都有点麻烦,也可以在创建UserControl的时候,把自身实例赋值给PictureBox的Tag属性,点击时直接取Tag:
private void form1_Load(object sender, EventArgs e) { var uc1 = new UserControl1(); uc1.Name = "UC_01"; // 将UserControl实例赋值给PictureBox的Tag uc1.pictureBox1.Tag = uc1; uc1.pictureBox1.Click += item_click; this.Controls.Add(uc1); uc1.Location = new Point(20, 20); var uc2 = new UserControl1(); uc2.Name = "UC_02"; uc2.pictureBox1.Tag = uc2; uc2.pictureBox1.Click += item_click; this.Controls.Add(uc2); uc2.Location = new Point(20, 120); } private void item_click(object sender, EventArgs e) { PictureBox clickedPic = sender as PictureBox; if (clickedPic != null) { // 从Tag里取出UserControl实例 UserControl1 targetUC = clickedPic.Tag as UserControl1; if (targetUC != null) { MessageBox.Show($"点击了UserControl:{targetUC.Name}"); } } }
这个方案代码也很少,但Tag是个通用属性,如果后续其他逻辑也用到了PictureBox的Tag,可能会产生冲突,需要注意避免。
内容的提问来源于stack exchange,提问作者Kaustubh Patange

