2010-08-06 2 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, поскольку я не могу самоподписываться). Это не зависит от пользователя моего компонента, который делает правильную вещь - вызывая Dispose, если они используют ShowDialog.

Я также подписываюсь в событии 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(). Etcetera.

Смежные вопросы