我有一个.NET 1.1。应用程序通过定制的翻译系统提供字符串资源,看起来有点像这样:
interface ITranslationProvider
{
string GetTranslation(string key);
event LanguageChangedEvent LanguageChanged;
}
ie:语言可以在运行时更改,组件需要通过更新显示字符串来响应。
单个翻译提供程序会持续应用程序的生命周期,而使用翻译服务的Windows窗体组件会动态创建。如果我编写使用此功能的表单组件,何时是取消订阅LanguageChanged
事件的正确时间?
Disposing()
应该起作用:
class MyPanel : System.Windows.Forms.Panel
{
public MyPanel(ITranslationProvider translator)
{
this.translator = translator;
translator.LanguageChanged += new LanguageChangedEvent(SetText);
SetText();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
// is this the correct place to unregister? will Dispose() get
// called on this panel, even though the translator's event has
// a reference to it?
translator.LanguageChanged -= new LanguageChangedEvent(SetText);
}
private void SetText()
{
this.Text = translator.GetTranslation("my.panel.text");
}
private ITranslationProvider translator;
}
...但我无法找到这个是否安全的明确答案。有任何想法吗?
答案 0 :(得分:2)
当处理其父表单时,您的控件将为Dispose
。
如果您通过致电Show()
来显示表单,.Net将在关闭时自动处理。
如果您致电ShowDialog()
,则您有责任处理该表单,可能是using
块。 (您应该在任何情况下处理该表单,即使它不添加事件处理程序)
答案 1 :(得分:1)
是的,使用Disposing()很好。如果客户端代码混淆了它,那么它就不会被调用,那么由于句柄泄漏会导致更大的问题。
请注意,这些“反向事件”很难处理。如果您知道事件源总是超过消费者,则回调可以是更合适的解决方案。一个示例接口声明:
public interface ITranslatableControl {
void SetText();
}
public MyPanel : Panel, ITranslatableControl {
public MyPanel() {
TranslationManager.RegisterControl(this);
}
void SetText() {
this.Text = TranslationManager.GetText(this, "mumble");
}
}
public static class TranslationManager {
private List<ITranslatableControl> controls;
public void RegisterControl(ITranslatableControl text) {
Control ctl = (Control)text;
ctl.Disposed += delegate { controls.Remove(text); }
controls.Add(text);
text.SetText(); // optional
}
}
请注意,如何收听Disposed事件,管理员可以从注册的控件列表中自动删除控件。忘记覆盖Disposing,客户端控件再也无法搞砸了。在语言更改时,只需迭代列表并调用SetText()方法。另请注意,如果控件具有多个可翻译字符串,您现在可以为同一控件注册多个回调。现在还允许您在Register方法中指定字符串的键,并将转换作为SetText()的参数提供。等等。
答案 2 :(得分:0)
我个人更喜欢取消订阅HandleDestroyed事件中的外部事件(因为我不喜欢自我订阅,所以使用OnHandleDestroyed覆盖)。这不依赖于我的组件的用户做正确的事情 - 如果他们使用ShowDialog则调用Dispose。
我也订阅了HandleCreated事件,因为可以多次调用ShowDialog(Show不能调用)。