Отказ от подписки компонентов Forms из долгоживущих источников событий - когда? - PullRequest
0 голосов
/ 06 августа 2010

У меня есть .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;
}

... но я не могу найти однозначного ответа на вопрос, безопасно это или нет. Есть идеи?

Ответы [ 3 ]

2 голосов
/ 06 августа 2010

Ваш контроль будет Dispose d, когда будет удалена его родительская форма.

Если вы показываете форму, позвонив по номеру Show(), .Net автоматически удалит ее, когда она закроется. Если вы звоните ShowDialog(), вы несете ответственность за удаление формы, предположительно в блоке using. (Вы должны утилизировать форму в любом случае, даже если она не добавляет обработчики событий)

1 голос
/ 06 августа 2010

Да, использовать 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 позволяет менеджеру автоматически удалять элемент управления из списка зарегистрированных элементов управления.Клиентский элемент управления больше не может испортить это, забыв переопределить удаление.При смене языка просто переберите список и вызовите метод SetText ().Также обратите внимание, что теперь вы можете зарегистрировать несколько обратных вызовов для одного и того же элемента управления, если элемент управления имеет более одной переводимой строки.Что теперь также позволяет указать ключ для строки в методе Register и предоставить перевод в качестве аргумента для SetText ().Etcetera.

0 голосов
/ 06 августа 2010

Лично я предпочитаю отписаться от внешних событий в событии HandleDestroyed (с переопределением OnHandleDestroyed, так как я ненавижу самостоятельную подписку). Это не полагается на то, что пользователь моего компонента делает правильную вещь - вызывает Dispose, если они использовали ShowDialog.

Я также подписываюсь на событие HandleCreated, потому что ShowDialog может быть вызван несколько раз (когда Show не может).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...