Unsubscribing Forms components from long-lived event sources - when?

删除回忆录丶 提交于 2019-12-12 01:29:56

问题


I have a .NET 1.1. application which provides string resources through a bespoke translation system that looks a little like this:

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

ie: language can change at runtime, and components need to respond by updating display strings.

A single translation provider lasts the lifetime of the application, whereas Windows Forms components that consume translation services get created dynamically. If I write forms components that use this, when is the correct time to unsubscribe from the LanguageChanged event?

for example, it seems like overriding Disposing() should work:

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;
}

... but I can't find a definitive answer to whether this is safe or not. Any ideas?


回答1:


Your control will be Disposed when its parent form is disposed.

If you show the form by calling Show(), .Net will automatically dispose it when it's closed.
If you call ShowDialog(), you are responsible for disposing the form, presumably in a using block. (You should dispose the form in any case, even if it doesn't add event handlers)




回答2:


Yes, using Disposing() is fine. If the client code messes this up so it doesn't get called then it has much bigger problems due to the handle leak.

Note that these kind of "reverse events" are awkward. If you know that the event source always out-lives the consumer then a callback can be to more appropriate solution. An example interface declaration:

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
    }
}

Note how listening to the Disposed event allows the manager to automatically remove the control from the registered controls list. The client control can no longer mess this up by forgetting to override Disposing. On a language change, simply iterate the list and call the SetText() method. Also note that you now can register multiple callbacks for the same control, in case a control has more than one translatable string. Which now also allows you to specify the key for the string in the Register method and supply the translation as an argument for SetText(). Etcetera.




回答3:


Personally I prefer to unsubscribe from external events in the HandleDestroyed event (with the OnHandleDestroyed override since I loath self-subscription). This doesn't rely on the user of my componant doing the right thing--calling Dispose if they used ShowDialog.

I also subscribe in the HandleCreated event because ShowDialog can be invoked multiple times (where Show cannot).



来源:https://stackoverflow.com/questions/3424516/unsubscribing-forms-components-from-long-lived-event-sources-when

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!