2010-08-06 43 views
0

我有一个.NET 1.1。应用程序,它通过一个定制的翻译系统,看起来有点像这样提供字符串资源:取消订阅来自长期事件源的表单组件 - 何时?

interface ITranslationProvider 
{ 
    string GetTranslation(string key); 
    event LanguageChangedEvent LanguageChanged; 
} 

即:语言可以在运行时更改和组件需要通过更新显示字符串回应。

单个翻译提供程序将持续应用程序的生命周期,而使用翻译服务的Windows Forms组件会动态创建。如果我编写使用此表单的组件,何时是退订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; 
} 

...但我无法找到一个明确的答案,这是否是安全与否。有任何想法吗?

回答

2

当您处理其父表单时,您的控制权将为Dispose d。

如果您通过调用Show()来显示表单,.Net将在关闭时自动处理它。
如果您致电ShowDialog(),则需要负责处理该表格,推测可能在using区块中。 (即使它不添加事件处理程序,也应该处理表单)

0

个人而言,我更喜欢在HandleDestroyed事件(使用OnHandleDestroyed覆盖,因为我不喜欢自我订阅)中取消订阅外部事件。这不依赖于我的组件的用户做正确的事情 - 如果他们使用ShowDialog调用Dispose。

我也在HandleCreated事件中订阅,因为ShowDialog可以被多次调用(其中Show不能)。

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()的参数提供。等等。