Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Разработка Windows Forms > менеджер форм


Автор: darkness 9.6.2007, 14:49
Надобно создать некоторый менеджер форм в MDI-приложении отслеживающий какие формы открыты, те сделать Activate, а какие закрыты те конечно Show
Дело в том, что мне нужно отследить не просто открыта ли это форма или нет (проверка Form.Name), но и ещё с каким параметром. Почему так заумно? Дело в том, что некий DataGridView хранит  таблицу, при двойном щелчке на любой Cell открывается  форма отображающая подробную информацию об объекте который описан в "щёлкнутой" записе в Гриде... Т.е. в форму с подробной инфой  передаются некоторые параметры, на основании чего она и формируется... Если с таким параметорм такая форма уже существует, то её просто надо активировать, если же нет, то завново родить.

Задача в принципе несложная. Решил я её через коллекцию (List) структуры, хранящую в себе параметр и само имя, а так же ссылку формы... Код получился немного громоздкий, но всё же рабочий. smile 
Потом возник вопрос: А можно ли отследить запущенные формы по нажатым контроллам, которые из вызвали. Особенно интересует подобный механизм в DataGridView ?

Как вы себе это представляете ?

Автор: Exception 10.6.2007, 17:17
Я бы взял за основу http://forum.vingrad.ru/sources/topic-154181.html и модифицировал под свои нужды. В частности, формы следовало бы хранить не в словаре с ключом-строкой, а в словаре с ключом-объектом.
Пусть у нас есть классы Animal, Fish и Bird и отображающие информацию о них дочерние MDI-формы AnimalViewerForm, FishViewerForm и BirdViewerForm.
Для того, чтобы формы можно было создавать, не зная конкретного типа, мы создадим интерфейс IViewer<T>, и пускай каждая из этих форм его реализует:
Код
public interface IViewer<T>
{
    T HoldObject { get; set; }
}

Таким образом, форма AnimalViewerForm должна реализовывать IViewer<Animal> и хранить экземпляр класса Animal:
Код
public class AnimalViewerForm : Form, IViewer<Animal>
{
    private Animal holdAnimal;
    public Animal HoldObject // свойство интерфейса!
    {
        get { return this.holdAnimal; }
        set
        {
            if (value == null) throw new ArgumentNullException ("value");
            this.holdAnimal = value;
            RefreshUI (); // объект изменился - обновляем интерфейс
        }
    }
    private void RefreshUI ()
    {
        this.nameTextBox.Text = this.holdAnimal.Name;
    }
}

По сути, теперь после создания любой формы нужно установить её свойство HoldObject (и пользовательский интерфейс обновится).
Теперь мы реализуем хранилище дочерних форм:
Код
public class MdiForm : Form
{
    private Dictionary<object, Form> childForms = new Dictionary<object, Form> ();
    private TForm GetForm<TForm, TKey> (TKey key)
        where TForm : Form, IViewer<TKey>, new()
    {
        TForm form = this.childForms[key] as TForm;
        if (form == null)
        {
            form = new TForm ();
            form.HoldObject = key;
            form.MdiParent = this;
            this.childForms[key] = form;
        }
        return form;
    }
    private void RemoveForm (object key)
    {
        Form form = this.childForms[key];
        if (form != null)
        {
            form.Dispose ();
            this.childForms.Remove (key);
        }
    }
}

Функция GetForm возратит либо уже созданную форму, либо новую, ассоциированную с объектом key (для каждого объекта будет существовать только одна форма). Функцию RemoveForm я не стал делать обобщённой, потому что реальная проверка соответствия типов нужна только при добавлении в коллекцию.
Теперь можно написать:
Код
this.GetForm<AnimalViewerForm, Animal> (new Animal ("Elephant")).Show (); // создаст новую дочернюю форму и отобразит её
this.GetForm<Animal, AnimalForm> (new Animal ("Elephant")).Hide (); // спрячет уже существующую форму

Автор: Exception 10.6.2007, 17:45
Кстати, пример со слоном сработает только если мы переопределим метод Equals() в классе Animal.

Автор: darkness 12.6.2007, 01:49
Exception, а теперь выношу на критику мой код - "небрежный плод моих забав"  smile 

Код


private Form1 MainForm;  //содержит ссылку на родителя MDI

private struct openforms    //структура которая хранит неюбходимые данные
       {
           public string form;    // Имя формы
           public string parametr;  // Параметр, с которым она была вызвана
           public int? hash;         // его высочество хэш данной формы
           public Form ref_form;  // ну и сам адрес в памяти 
           openforms(string form, string parametr)
           {
               this.form = form;
               this.parametr = parametr;
               this.ref_form = null;
               this.hash = null;         
           }
       }

List<openforms> forms = new List<openforms>();   

На мой взгляд, лишнего ничего структура не содержит, это будет видно ниже...
Далее пишем несколько вспомогательных методов(предикаты, и метод создания формы):
Код

private bool real(openforms struc2)
       {
           return this.first.form==struc2.form&&this.first.parametr==struc2.parametr;
       }


        private bool real1(openforms struc3)
        {
            return this.first.hash == struc3.hash; 
        }


        private Form FShow(Form ch)
        {
            ch.MdiParent =  ;
            ch.Show();
            this.StopForm(ch);
            return ch;
        }

Ну и наконец именно то, что и будет рулить нашими всеми формами:
Код

    public  void FSParam(Form f, string str)
        {
            this.first.form=f.Name;
            this.first.parametr=str;
          
            if (forms.Find(new Predicate<openforms>(real)).form == null)  
            {
               //если такой формы с таким параметром нет, то создаём и заносим в коллекцию
                this.first.ref_form = this.FShow(f);
                this.first.hash = this.first.ref_form.GetHashCode();
                forms.Add(this.first);
            }
            else
            {
             //а ежели всё-таки таковая имеется, то просто её активируем
               forms.Find(new Predicate<openforms>(real)).ref_form.Activate();
            }     
        }

Вот.
Ну ещё один из важных моментов, это проследить закрытие формы,  а следовательно избавиться от лишней записи
в forms
Код

public void f_FormClosing(object sender, FormClosingEventArgs e)
        {
            forms.Remove(forms.Find(new Predicate<openforms>(real1)));
        }


Вот в принципе и всё....
Что скажете?




Автор: Exception 12.6.2007, 17:04
ИМХО, моё решение получше будет.
Во-первых, я плохо понимаю, зачем хранить хэш формы -- у тебя же, по сути, каждая форма и так уникально идентифицируется переданным ей параметром?
Во-вторых, для изменения типа параметра придётся поменять код (а у меня этого не требуется).
В-третьих, а почему ты используешь строковой параметр? Не лучше ли передавать данные в каком-нибудь специально предназначенном для каждой формы классе?
В-четвёртых, твоё решение, по очевидным причинам, медленнее (поиск с предикатами работает медленнее, чем выборка по ключу).

Автор: darkness 13.6.2007, 02:11
Exception, 
Цитата

зачем хранить хэш формы

согласен. на выспавшуюся голову гораздо чётче видно обстановку  smile 
Цитата

для изменения типа параметра придётся поменять код

для изменения типа параметра  какого? который string? для моих нужд он всегда будет string...
Цитата

Не лучше ли передавать данные в каком-нибудь специально предназначенном для каждой формы классе?

У меня это строка отправляется потом с запросом в базу....
Цитата

поиск с предикатами работает медленнее, чем выборка по ключу

Вразумил, посему заюзую Dictionary, когда буду править! smile  Спасибо! 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)