Модераторы: Partizan, gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Событие на массив объектов 
:(
    Опции темы
dezmond06
Дата 26.3.2011, 15:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 26.3.2011

Репутация: нет
Всего: нет



Есть учебная работа по С#. Задание такое - есть массив объектов Студент с полями Стипендия, факультет и т.д., в общем стандартная мура.
Задача проги, чтобы при нажатии кнопок PgUp, PgDn и Esc. стипендия всех студентов увелич. на 20%, уменьшалась на 20% и программа закрывалась соответственно. Реализовать надо событиями и делегатами.
В общем что-то оно пытается работать, но вяленько. Принудительно вызываю событие, нажатие кнопок оно принимает, но меняет поле только у одного (первого) члена массива. Остальные на месте. Мне кажется тут что-то с областью видимости переменных, но где - не могу понять. В отладчике прогоняю, все члены инициализируются, обработчики цепляются.

Класс, объявляющий события:
Код


    public delegate void Pushing(object sender, ChangedEventArgs chgargs);
    public delegate void LooserDeleting(ref Student[] stt);

    public class Eventing
    {
        Pushing[] ButtonChange = new Pushing[3];

        private ChangedEventArgs evargs = new ChangedEventArgs(); //класс, производный от EventArgs

        public event Pushing KeyPush
        {
            add
            {
                for (int i = 0; i < 3; i++)
                {
                    if (ButtonChange[i]==null)
                    {
                        ButtonChange[i] = value;
                        break;
                    }
                }
            }
            remove
            {
                for (int i = 0; i < 3; i++)
                {
                    if (ButtonChange[i] == value)
                    {
                        ButtonChange[i] = null;
                        break;
                    }
                }
            }
        }

        public event LooserDeleting LooDel;

        public void OnPush(ChangedEventArgs args)
        {
            ConsoleKeyInfo rk = new ConsoleKeyInfo();
            rk = Console.ReadKey(true);
            switch (rk.Key)
            {
                case ConsoleKey.PageUp: { if (ButtonChange[0] != null) ButtonChange[0](this, args); break; }
                case ConsoleKey.PageDown: { if (ButtonChange[1] != null) ButtonChange[1](this, args); break; }
                case ConsoleKey.Escape: { if (ButtonChange[2] != null) ButtonChange[2](this, args); break; }
                default:
                    break;
            }
        }
    }


Фрагмент класса-приемника с обработчиками (Студент):
Код


 public class Student : IComparable
    {
        string fam, studfac;
        double scholarship;
        public int[] marks = new int[6];
        Eventing StudEvent;

        public Student(Eventing ev)
        {
          StudEvent = ev;
          StudEvent.KeyPush += new Pushing(PgUp);
          StudEvent.KeyPush += new Pushing(PgDn);
          StudEvent.KeyPush += new Pushing(ExitAppDel);
        }
        public void PgDn(object sender, ChangedEventArgs args)
        { this.grant *= 0.8; }

        public void PgUp(object sender, ChangedEventArgs args)
        { this.grant *= 1.2; }

        public void ExitAppDel(object sender, ChangedEventArgs args)
        { Environment.Exit(0); }


Фрагменты процедуры Main:

Код

               ...
            Student[] studs = new Student[sts.Length-1];
            Eventing evv = new Eventing(); //событийный класс
            for (int i = 0; i < sts.Length-1; i++)
            {
                studs[i] = new Student(evv); }
            ...
            output(facults, studs, mt); //вывод значений массива
            ChangedEventArgs argss = new ChangedEventArgs();
            int k = 1;
            while (k > 0)
            {
                evv.OnPush(argss); //в цикле принудительно вызываем событие
                                          //понимаю, что маразм, но как                  //правильно  сделать - заклинило.
                output(facults, studs, mt);
            }


Смысл такой, надо чтобы прога постоянно ждала нажатия клавиши, при нажатии увелич/уменьшала стипендию сразу выводила результаты и опять продолжала ждать.
Помогите, плиз!

Это сообщение отредактировал(а) dezmond06 - 26.3.2011, 16:14
PM MAIL   Вверх
dezmond06
Дата 28.3.2011, 14:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 26.3.2011

Репутация: нет
Всего: нет



Неужели никаких мыслей нет???  smile 
Задачка-то вроде несложная.
Я уж все пересмотрел. Главное, что обработчик на escape срабатывает, то бишь из программы выходит. Да и на первый элемент массива все работает, и увеличение, и уменьшение.
Подозреваю, что что-то где-то не там объявил, а где - фиг его знает. Может, на каждый объект массива надо создавать свой экземпляр события??? Хотя тоже пробовал вроде...

Это сообщение отредактировал(а) dezmond06 - 28.3.2011, 14:09
PM MAIL   Вверх
diadiavova
Дата 28.3.2011, 14:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доктор Зло(диагност, настоящий, с лицензией и полномочиями)
****


Профиль
Группа: Модератор
Сообщений: 5821
Регистрация: 14.8.2008
Где: В Коньфпольте

Репутация: 18
Всего: 142



dezmond06, ты уменьшаешь и увеличиваешь стипндию так
Код

this.grant *= 0.8;
и так соответственно
Код

this.grant *= 1.2;

однако, что такое grant из твоего кода непонятно(или я пропустил). В любом случае, если тебе надо внести изменения в весь список, то надо обходить весь массив или например воспользоваться Array.ForEach. Ты же меняешь значение grant, очевидно это и есть первый элемент.


--------------------
Хочешь получить мудрый совет - читай подписи участников форумов.
Злой доктор Щасзаболит smile
PM   Вверх
dezmond06
Дата 28.3.2011, 16:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 26.3.2011

Репутация: нет
Всего: нет



Я привел не весь код класса Student, в принципе там ничего интересного, но для чистоты эксперимента:

Код


    public class Student : IComparable
    {
        string fam, studfac;
        double scholarship;
        public int[] marks = new int[6];
        public Eventing StudEvent;

        public Student(Eventing ev)
        {
          StudEvent = ev;
          StudEvent.KeyPush += new Pushing(PgUp);
          StudEvent.KeyPush += new Pushing(PgDn);
          StudEvent.KeyPush += new Pushing(ExitAppDel);
        }
        public void PgDn(object sender, ChangedEventArgs argg)
        { this.grant *= 0.8; }

        public void PgUp(object sender, ChangedEventArgs argg)
        { this.grant *= 1.2; }

        public void ExitAppDel(object sender, ChangedEventArgs argg)
        { Environment.Exit(0); }

        public int CompareTo(Object obj)
        {
            Student srav = obj as Student;
            if (srav.Equals(null)) throw new ArgumentException();
            if (studfac.CompareTo(srav.studfac) == 0) return 1;
            else if (studfac.CompareTo(srav.studfac) < 0) return -1;
            else return 0;
        }

        public bool isAchiever
        {
            get
            {   for (int i = 0; i < 7; i++) if (Array.IndexOf(marks, i) > 0) return false;
                return true;
            }
        }

        public bool isLooser
        {
            get
            {
                for (int i = 0; i < 3; i++) if (Array.IndexOf(marks, i) > 0) return true;
                return false;
            }
        }

        public string fams
        { get { return fam; }
          set { fam = value; }
        }
        public string facs
        {
            get { return studfac; }
            set { studfac = value; }
        }

        public double grant
        {
            get { return scholarship; }
            set { scholarship = value; }
        }


        public double avgball
        {
            get
            {   double av=0; 
                for (int i = 0; i < marks.Length; i++)
              { av = av + marks[i];}
                return av / marks.Length;
              }
        }
    }
}


Grant - примитивное свойство для доступа к полю scholarship. Но метод-обработчик (PgDn) объявлен-то у нас как динамич. метод класса, а не как статический, значит и вызываться и ловить событие он должен для каждого экземпляра класса Студент. Или я не прав?
Пересмотрел кучу примеров (Шилдта, Рихтера и прочих), класс события создается вроде бы 1 раз у всех и ловить его должны все получатели, подписанные на него. Может быть я неверно подписываю? в конструкторе? может это надо делать не там? 
Делегаты объявлены вне классов, в namespace. Экземпляр события создается в main.
Что я делаю не так?

Это сообщение отредактировал(а) dezmond06 - 28.3.2011, 16:25
PM MAIL   Вверх
diadiavova
Дата 28.3.2011, 16:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доктор Зло(диагност, настоящий, с лицензией и полномочиями)
****


Профиль
Группа: Модератор
Сообщений: 5821
Регистрация: 14.8.2008
Где: В Коньфпольте

Репутация: 18
Всего: 142



dezmond06, я сразу не понял чего ты там делал. Просто несколько странно, для такой простой операции такую громадину сооружать. Кроме того, я так и не понял зачем это все. На самом деле впихивать в класс Student события ни к чему. Скорее надо либо создать класс, который будет вмещать всю коллекцию и у него в случае необходимости создать метод, которых будет изменять значение данного свойства всех студентов на заданную величину. Или делать это прямо в форме к примеру в обработчиках соответствующих событий. Собственно для того, чтобы это сделать надо всего лишь написать что-то вроде
Код

Array.ForEach(studs, x => x.grant *= 1.2)

И все элементы массива изменяться, к тому же не придется жестко привязывать эти действия к конкретным коэффициентам.


--------------------
Хочешь получить мудрый совет - читай подписи участников форумов.
Злой доктор Щасзаболит smile
PM   Вверх
dezmond06
Дата 29.3.2011, 08:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 26.3.2011

Репутация: нет
Всего: нет



Цитата(diadiavova @ 28.3.2011,  16:35)
dezmond06, я сразу не понял чего ты там делал. Просто несколько странно, для такой простой операции такую громадину сооружать. Кроме того, я так и не понял зачем это все. На самом деле впихивать в класс Student события ни к чему. Скорее надо либо создать класс, который будет вмещать всю коллекцию и у него в случае необходимости создать метод, которых будет изменять значение данного свойства всех студентов на заданную величину. Или делать это прямо в форме к примеру в обработчиках соответствующих событий. Собственно для того, чтобы это сделать надо всего лишь написать что-то вроде
Код

Array.ForEach(studs, x => x.grant *= 1.2)

И все элементы массива изменяться, к тому же не придется жестко привязывать эти действия к конкретным коэффициентам.

В том то и дело, что это не моя прихоть, а исключительно требование по заданию, если буквально, то вот цитата:
"...
Класс  Студент должен содержать следующие элементы:...метод-обработчик события нажатия клавиши PageUp, метод-обработчик события нажатия клавиши PageDown..."
Я и сам люблю оптимизировать код, но в данном случае требуется выяснить, почему не работает мой способ, а не предлагать альтернативный.
Ведь, таким образом, как у меня МОЖНО реализовать, и ничего экстраординарного тут нет.
Так что создавать отдельный класс для массива студентов не годится.
PM MAIL   Вверх
diadiavova
Дата 29.3.2011, 11:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доктор Зло(диагност, настоящий, с лицензией и полномочиями)
****


Профиль
Группа: Модератор
Сообщений: 5821
Регистрация: 14.8.2008
Где: В Коньфпольте

Репутация: 18
Всего: 142



dezmond06, Если я правильно понял задачу, то вот тебе упрощенный пример.

Присоединённый файл ( Кол-во скачиваний: 3 )
Присоединённый файл  arrayevent.rar 24,45 Kb


--------------------
Хочешь получить мудрый совет - читай подписи участников форумов.
Злой доктор Щасзаболит smile
PM   Вверх
dezmond06
Дата 30.3.2011, 11:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 26.3.2011

Репутация: нет
Всего: нет



Цитата(diadiavova @ 29.3.2011,  11:24)
dezmond06, Если я правильно понял задачу, то вот тебе упрощенный пример.

Спасибо большое, заработало. Правда сделано все совсем не так, как у меня, но зато работает.
EventHandler - это встроенный делегат. А со своим реально сделать?
И еще вопросик: как повесить на событие статический метод, мне нужно удалить двоечников из массива.
Я делаю по вашему образцу, сделал отдельный класс для аргументов события:
Код

public class DelEventArgs : EventArgs
    {
        public DelEventArgs(Key key, Student[] sts)
        {
            this.Key = key;
            this.stut = new Student[sts.Length];
            for (int i = 0; i < sts.Length; i++)
            {
             stut[i] = new Student(new Eventing());
         stut[i] = sts[i];
             Console.WriteLine(stut[i].fams); // тут заполнилось все нормально, массив корректен
            }
        }
        public Key Key { get; private set; }
        public Student[] stut;
    }


Создал метод для вызова события: 
[code=csharp]
        public void OnPushDel(DelEventArgs drr)
        {
            if (PushDel != null)
                PushDel(null, drr);
        }/code]

В классе program сделал статич. поле события и вешаю на него обработчик - статич. метод класса program:

 
Код
   class Program
    {
        static Eventing evv = new Eventing();
        
        static void Main(string[] args)
        {
            evv.PushDel += new EventHandler<DelEventArgs>(Program.Deleting);

Далее соответствующая ветка case:
Код

                        case ConsoleKey.Delete:
                        DelEventArgs ddr = new DelEventArgs(Key.Delete, studs);
                        evv.OnPushDel(ddr);
                        output(facults, ddr.stut, mt);
                        break;

А вот сам метод удаления:
Код

        static void Deleting(object sender, DelEventArgs darr)
        {   int k=0;
            for (int i = 0; i < darr.stut.Length-1; i++)
            {
                Console.WriteLine(darr.stut[i].fams); //а тут все члены одинаковы
                if (darr.stut[i].isLooser)
                {
                    Student tmp = darr.stut[i];
                    darr.stut[i] = darr.stut[i + 1];
                    darr.stut[i + 1] = tmp;
                }
            }
            Array.Resize(ref darr.stut, darr.stut.Length - k);
        }

Событие срабатывает, но массив заполняется почему-то неправильно. Во все члены записывается один и тот же студент, опять что-то с областью видимости намутил, наверное.
Скажите, как лучше осуществить передачу массива для последующей обработки? Может как-нибудь через ref-параметры, вместо того, чтобы с классом DelEventArgs возиться?


Это сообщение отредактировал(а) dezmond06 - 30.3.2011, 11:09
PM MAIL   Вверх
diadiavova
Дата 30.3.2011, 11:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доктор Зло(диагност, настоящий, с лицензией и полномочиями)
****


Профиль
Группа: Модератор
Сообщений: 5821
Регистрация: 14.8.2008
Где: В Коньфпольте

Репутация: 18
Всего: 142



Цитата(dezmond06 @  30.3.2011,  12:07 Найти цитируемый пост)
А со своим реально сделать?

Без разницы абсолютно, просто в данном случае свой создавать не требуется.
Цитата(dezmond06 @  30.3.2011,  12:07 Найти цитируемый пост)
Я делаю по вашему образцу, сделал отдельный класс для аргументов события:

Ну то, что ты в классе аргументов выполняешь вывод на консоль и еще чего-то - это точно не мой образец. Аргументы события должны передавать в обработчик дополнительную информацию о событии. И не более того.
Цитата(dezmond06 @  30.3.2011,  12:07 Найти цитируемый пост)
мне нужно удалить двоечников из массива

А почему их просто не отфильтровать?
Код

studs = studs.Where(x => ! isLooser).ToArray() // кстати правильно писать Loser

Или как-то так. Зачем мудрить? 


--------------------
Хочешь получить мудрый совет - читай подписи участников форумов.
Злой доктор Щасзаболит smile
PM   Вверх
dezmond06
Дата 30.3.2011, 15:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 26.3.2011

Репутация: нет
Всего: нет



Цитата(diadiavova @ 30.3.2011,  11:23)
Цитата(dezmond06 @  30.3.2011,  12:07 Найти цитируемый пост)
А со своим реально сделать?

Без разницы абсолютно, просто в данном случае свой создавать не требуется.
Цитата(dezmond06 @  30.3.2011,  12:07 Найти цитируемый пост)
Я делаю по вашему образцу, сделал отдельный класс для аргументов события:

Ну то, что ты в классе аргументов выполняешь вывод на консоль и еще чего-то - это точно не мой образец. Аргументы события должны передавать в обработчик дополнительную информацию о событии. И не более того.
Цитата(dezmond06 @  30.3.2011,  12:07 Найти цитируемый пост)
мне нужно удалить двоечников из массива

А почему их просто не отфильтровать?
Код

studs = studs.Where(x => ! isLooser).ToArray() // кстати правильно писать Loser

Или как-то так. Зачем мудрить?

Ну вывод-то понятно, что это для отладки ))

А как передать в метод массив объектов для обработки, если не через аргументы, то как? Это-то я и спрашивал.
А фильтрация ваша на LINQ написана? 

P.S. Полдключил System.Xml.Linq - все равно выводит ошибку при компиляции

"Error    1    'System.Array' does not contain a definition for 'Where' and no extension method 'Where' accepting a first argument of type 'System.Array' could be found (are you missing a using directive or an assembly reference?)"

Это сообщение отредактировал(а) dezmond06 - 30.3.2011, 16:03
PM MAIL   Вверх
dezmond06
Дата 30.3.2011, 16:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 26.3.2011

Репутация: нет
Всего: нет



Все разобрался, заработало. Конечно же мне никто не удосужился объяснить, что для использования линка нужно подключить референс System.Core, что по умолчанию он в консоли не подключается ))

Да и синтаксис лямбда-выражения у вас немного неверен, надо 
darr.stut = darr.stut.Where(x =>!x.isLoser).ToArray();

Но все равно очень помогли, большое спасибо!
PM MAIL   Вверх
diadiavova
Дата 30.3.2011, 17:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доктор Зло(диагност, настоящий, с лицензией и полномочиями)
****


Профиль
Группа: Модератор
Сообщений: 5821
Регистрация: 14.8.2008
Где: В Коньфпольте

Репутация: 18
Всего: 142



Цитата(dezmond06 @  30.3.2011,  17:22 Найти цитируемый пост)
Конечно же мне никто не удосужился объяснить, что для использования линка нужно подключить референс System.Core, что по умолчанию он в консоли не подключается ))

Вообще-то в шаблонах проектов все подключено, но в любом случае это уже совсем другой вопрос. Почему кто-то должен был отвечать на вопрос, который не задавался?
Цитата(dezmond06 @  30.3.2011,  17:22 Найти цитируемый пост)
Да и синтаксис лямбда-выражения у вас немного неверен, надо 

От руки набрал, малость ошибся, в любом случае это был не код для копипасты, а пример того, как сделать лучше. Предполагалось, что синтаксис тебе известен.


--------------------
Хочешь получить мудрый совет - читай подписи участников форумов.
Злой доктор Щасзаболит smile
PM   Вверх
dezmond06
Дата 30.3.2011, 22:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 26.3.2011

Репутация: нет
Всего: нет



Может, я не писал, но я в дотнете только начинаю, так что далеко не все очевидное для вас очевидно для меня  smile 
У меня в шаблоне консольного приложения автоматом Сore не подключается (стоит VS2008 Express).
В любом случае, это ни в коем случае не недовольство.
Еще раз спасибо за помощь, а то на других форумах голый вассер - на programmersforum и sql.ru - 100 просмотров и ни одного ответа, одно словоблудие.
PM MAIL   Вверх
diadiavova
Дата 30.3.2011, 23:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доктор Зло(диагност, настоящий, с лицензией и полномочиями)
****


Профиль
Группа: Модератор
Сообщений: 5821
Регистрация: 14.8.2008
Где: В Коньфпольте

Репутация: 18
Всего: 142



Цитата(dezmond06 @  30.3.2011,  23:51 Найти цитируемый пост)
У меня в шаблоне консольного приложения автоматом Сore не подключается (стоит VS2008 Express).

Просто когда создаешь проект там надо выбирать целевой фреймворк 3.5, у тебя наверно более ранняя версия выбрана, поэтому в шаблоне и отсутствуют нужные ссылки.
Цитата(dezmond06 @  30.3.2011,  23:51 Найти цитируемый пост)
 на других форумах голый вассер - на programmersforum и sql.ru - 100 просмотров и ни одного ответа, одно словоблудие. 

Просто у тебя там много напутано и разобраться трудно. Проще надо все делать. smile 


--------------------
Хочешь получить мудрый совет - читай подписи участников форумов.
Злой доктор Щасзаболит smile
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
Partizan
PashaPash

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, Partizan, PashaPash.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | .NET для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.1084 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.