如何从自定义Control访问父窗体属性同时兼容设计时与运行时
问题根因
你原来的实现有两个核心问题:
- 控件构造函数执行时,控件尚未被添加到窗体的控件树中,此时无论设计时还是运行时,都无法获取到父窗体实例,因此构造函数中不能写访问父窗体属性的逻辑
Site属性仅在设计时环境下会被赋值,运行时该属性确实为null,自行维护ContainerControl的方案无法兼容运行时场景
可行实现方案
我们可以把语言初始化逻辑延后到控件挂载到父容器之后执行,使用控件自带的OnParentChanged方法,该方法在设计时和运行时都会在控件父容器变更时触发,同时可以用FindForm()方法直接获取控件所属的顶层窗体,无需自行处理Site属性。
第一步:修改窗体端代码,添加语言变更通知
首先给窗体的LanguageID添加属性变更通知,方便后续控件可以动态响应语言切换:
// 窗体类中的代码 public enum LanguageID { en, fr, de, it, ro } public class Language { public LanguageID LangID { get; set; } = LanguageID.en; public string TranslatedText { get; set; } = "One"; } // 将LanguageID从字段改为带变更通知的属性 private LanguageID _languageID = LanguageID.en; public LanguageID LanguageID { get => _languageID; set { if (_languageID == value) return; _languageID = value; // 触发语言变更事件 LanguageIDChanged?.Invoke(this, EventArgs.Empty); } } // 语言变更事件,供控件订阅 public event EventHandler LanguageIDChanged; [Browsable(false)] public Language[] Languages = new Language[]() { new Language { LangID = LanguageID.en, TranslatedText = "One" }, new Language { LangID = LanguageID.fr, TranslatedText = "Un"}, new Language { LangID = LanguageID.de, TranslatedText = "Einer"} // 其余语言以此类推 };
第二步:修改自定义控件代码
删除原来自行维护ContainerControl和重写Site属性的逻辑,改用OnParentChanged实现语言加载:
public class MyControl : Control { public MyControl() { // 不要在构造函数中访问父容器相关属性,此时控件尚未挂载 } protected override void OnParentChanged(EventArgs e) { base.OnParentChanged(e); // 获取控件所属的顶层窗体 var parentForm = this.FindForm(); // 替换为你实际的窗体类名 if (parentForm is not MyCustomForm targetForm) return; // 首次加载时更新语言 UpdateLanguage(targetForm); // 可选:订阅窗体语言变更事件,实现动态切换语言 targetForm.LanguageIDChanged += (s, args) => UpdateLanguage(targetForm); } private void UpdateLanguage(MyCustomForm form) { var selectedLang = Array.Find(form.Languages, l => l.LangID == form.LanguageID); if (selectedLang == null) return; // 此处编写你的控件属性设置逻辑,例如: this.Text = selectedLang.TranslatedText; } }
注意事项
- 如果不需要动态响应语言变更,可以删除事件订阅的相关代码,只保留首次加载时的更新逻辑即可
FindForm()方法支持嵌套在任意容器(Panel、UserControl等)中的控件,会自动递归查找顶层窗体,无需自行处理嵌套层级- 该方案同时兼容设计时和运行时,设计时修改窗体的
LanguageID属性,控件会自动刷新为对应语言的文本
内容的提问来源于stack exchange,提问作者Vali Maties
相关产品推荐
相关产品推荐

