none
Индексация элементов на WPF Canvas RRS feed

  • Вопрос

  • Если я определю в приложении WPF экземпляр класса Line, а затем добавлю его на канву

    Line myLine = new Line();
    myLine.Stroke = Brushes.Green;
    myLine.StrokeThickness = 1.0;
    myLine.X1 = 811.56;
    myLine.Y1 = 463.21;
    myLine.X2 = 912.35;
    myLine.Y2 = 463.21;
    this.ChartCanvas.Children.Add(myLine);

    т.е. нарисую на канве горизонтальный отрезок прямой, а затем возьму его индекс:

    myIndex = this.ChartCanvas.Children.IndexOf(myLine);

    а затем, определю прямоугольник:

    Point Point1 = new Point(1, 50);
    Point Point2 = new Point(50,50);
    Point Point3 = new Point(1,80);
    Point Point4 = new Point(50, 80);
    
    Polygon myRect = new Polygon();
    myRect.Stroke = Brushes.Red;
    myRect.StrokeThickness = 1.0;
    myRect.Fill = Brushes.Red;
    myRect.Points.Add(Point1);
    myRect.Points.Add(Point2);
    myRect.Points.Add(Point3);
    myRect.Points.Add(Point4);

    но не буду писать

    ChartCanvas.Children.Add(myRect);

    а напишу:

    ChartCanvas.Children.RemoveAt(myIndex);

    тем самым удалив отрезок прямой с канвы, а затем, напишу:

    ChartCanvas.Children[myIndex] = myRect;

    То прямоугольник myRect визуализируется на канве вместо удаленного отрезка прямой? И к нему можно будет иметь доступ по индексу myIndex или нет?

    19 июня 2012 г. 8:59

Ответы

  • ChartCanvas.Children.RemoveAt(myIndex);
    ChartCanvas.Children.Insert(myIndex, myRect);

    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    А вот этот вот мой ответ не является ответом на ваш вопрос? Вы сначала удаляете объект с индексом Х а потом вставляете в это же место новый. А что решение с идентификацией объектов по свойству Tag, а не по индексу в коллекции вам не нравится?

    Индексы не поплывут если эти 2 строки будут выполнятся друг за другом.


    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    • Изменено LXGDARKEditor 21 июня 2012 г. 12:17
    • Помечено в качестве ответа TownSparrow 21 июня 2012 г. 18:09
    21 июня 2012 г. 12:16
    Отвечающий

Все ответы

  • Э... Если у вас на канву после линии не добавлялись компоненты, то вы получите Exception. Т.к. в коллекции элемента с таким номером просто нет.

    Вызывайте Add и определяйте индекс также как вы это сделали для линии.

    19 июня 2012 г. 10:33
    Отвечающий
  • тем самым удалив отрезок прямой с канвы, а затем, напишу:
    ChartCanvas.Children[myIndex] = myRect;

    То прямоугольник myRect визуализируется на канве вместо удаленного отрезка прямой? И к нему можно будет иметь доступ по индексу myIndex или нет?

    Ну вы же строчкой ранее удалили его с канваса, а значит обратится к нему по индексу элементов канваса для присвоения нового значения не получится.

    Вот если ниже вашей фразы "но не буду писать" вместо приведенного вами кода добавить этот, то:

    1. Линия исчезнет, а прямоугольник появится

    2. Переменная myIndex будет иметь индекс теперь уже прямоугольника.

    ChartCanvas.Children.RemoveAt(myIndex);
    ChartCanvas.Children.Add(myRect);
    myIndex = this.ChartCanvas.Children.IndexOf(myRect);

    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    19 июня 2012 г. 10:42
    Отвечающий
  • Т.е. после вызова RemoveAt, индекс по которому удалялся элемент уже не существует? И это значение индекса может быть повторно назначено уже для нового элемента на канве? А вот можно каким-нибудь образом записать новый элемент на существующий индекс, что бы этот новый элемент по этому индексу был вместо старого?


    • Изменено TownSparrow 19 июня 2012 г. 11:02
    19 июня 2012 г. 11:01
  • Ну простой подменой у меня не получилось, так как заругался что индекс привязан к существующему Visual. А вот код как я написал выше работает и как я понимаю решает ваши задачи.

    И это значение индекса может быть повторно назначено уже для нового элемента на канве?

    В моем коде не значения индекса прививается новой фигуре, а индекс новой фигуры записывается в существующую переменную.

    Вам нужно что бы при подмене был тот же самый индекс фактически? Например была линия с индексом 5 и прямоугольник должен иметь тот же индекс?


    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    19 июня 2012 г. 11:06
    Отвечающий
  • Все разобрался. Что бы вставить новую фигуру в ту же позицию коллекции (то есть на тот же индекс), вместо моего кода више пишем этот:

    ChartCanvas.Children.RemoveAt(myIndex);
    ChartCanvas.Children.Insert(myIndex, myRect);

    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    • Помечено в качестве ответа TownSparrow 19 июня 2012 г. 11:53
    • Снята пометка об ответе TownSparrow 19 июня 2012 г. 11:55
    19 июня 2012 г. 11:24
    Отвечающий
  • Попробую.... Мне действительно нужно что бы при подмене был тот же самый индекс фактически. Например была линия с индексом 5 и прямоугольник должен иметь тот же индекс. Сейчас попробую ваш код.


    • Изменено TownSparrow 19 июня 2012 г. 11:32
    19 июня 2012 г. 11:31
  • Вроде работает. Но вот, например, записал я элемент по фиксированному индексу после выполнения RemoveAt(), а есть гарантия, что данное значение индекса система уже не будет использовать при последующих вызовах Add() ? Ведь после выполнения RemoveAt(), индекс (под которым был удален элемент) теряется. Ведь .NET Framework "не знает", что я уже принудительно использовал это значение. Или же перед присваиванием индекса элементу система выполняет какую-то проверку уже используемых индексов вне зависимости от того, как они были определены - ею или пользователем?




    • Изменено TownSparrow 19 июня 2012 г. 12:06
    19 июня 2012 г. 11:53
  • Тогда вместо RemoveAt выполняйте присвоение элементу значения null (либо сделайте свой null, например в классе какое-нибудь bool поле) и после проверяйте на null, тогда сохранится последовательность индексов.

    Для связи [mail]

    19 июня 2012 г. 12:25
  • А тогда скажите, пожалуйста, после выполнения RemoveAt() индекс, под которым удалился элемент обнуляется или что с ним делается?

    И второе. Вот, например, я создал экземпляр класса Line под именем myLine и пишу:

    this.ChartCanvas.Children.Add(myLine);

    int myIndex = this.ChartCanvas.Children.IndexOf(myLine);

    this.ChartCanvas.Children[myIndex] = null; // здесь myLine убирается вобще как при Remove?

    Затем, создал экземпляр класса Polygon под именем MyRect и пишу:

    this.ChartCanvas.Children[myIndex] = MyRect;

    Именно об этом случае вы пишете "тогда сохранится последовательность индексов"?

    С уважением   Евгений.

    19 июня 2012 г. 12:43
  • Именно об этом случае вы пишете "тогда сохранится последовательность индексов"?

    С уважением   Евгений.

    Принцип работы с этой коллекцией такой. Есть коллекция 1,2,3,4,5,6,7. Когда вы удаляете 3, то то что было 4 стало 3, что было 5 стало 4 и т.д. то есть идет сдвиг индексов. когда мы вставляем элемент не в конец коллекции а в указанное место он раздвигает соседей и занимает место этого индекса.

    Если же мы некий элемент под индексом 3 просто обнулим, то он место в коллекции занимать будет, но отображаться не будет. Потом его можно заменить на новый элемент, который будет показан. Если вам нужно такое поведение то вы все правильно поняли. Только вот вопрос - зачем вам резервировать место в коллекции?


    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    • Помечено в качестве ответа TownSparrow 20 июня 2012 г. 9:06
    • Снята пометка об ответе TownSparrow 21 июня 2012 г. 12:00
    19 июня 2012 г. 12:47
    Отвечающий
  • Дело в том, что я пишу приложение, которое, в частности, строит график биржевых котировок в виде свечей - свечной график. Длительность дневной торговой сессии - 7 часов. В течении всего этого времени должны отрисовываться свечи. Данные для каждой свечи собираются в течении 1 минуты. За минуту котировка может измениться несколько раз. Я фиксирую индекс на канве для тела (прямоугольника) и тени (вертикального отрезка прямой) каждой свечи. Каждую минуту с появлением очередной новой свечи у меня выполняется сдвиг графика (всех остальных свечей). И к их телам и теням (для изменения их координат по горизонтали) я доступаюсь через их индексы на канве. Причём, форма тела свечи на графике во время её отрисовки тоже может изменяться, скажем от горизонтального отрезка прямой до прямоугольника и наоборот. По-этому, в процессе отрисовки каждой свечи я не хочу плодить лишние значения индексов, а хочу писать изменения по уже существующим индексам. Хотя 32-х разрядное число Int32, которое является типом индекса элемента на канве, вряд ли переполниться, даже если бы я в течении 7 часов брал новый индекс при каждом изменении котировки внутри одноминутного интервала отрисовки очередной свечи. Я уж, честно сказать, подумываю сейчас, что пора мне прекращать выкаблучиваться, а брать новый индекс при каждом изменении  формы тела свечи при её отрисовке и всё будет проще. Вряд ли Int32 переполнится за 7 - 8 часов даже при таких условиях. Так наверное и сделаю, тем более, если кто-нибудь из вас посоветует. Как говорится одна голова - хорошо, а несколько - лучше. От полезных советов до сих пор было только добро. К стати, за поддержку и помощь - спасибо.
    • Изменено TownSparrow 19 июня 2012 г. 13:57
    19 июня 2012 г. 13:32
  • даже если бы я в течении 7 часов брал новый индекс при каждом изменении котировки внутри одноминутного интервала отрисовки очередной свечи.

    В каком смысле "брал" новый? Предположим одновременно на графике можно увидеть 100 свечей. При добавлении на график новых они появляются справа, а старые как бы скрываются за левой кромкой (а на деле удаляются) и по всему выходит что максимальное количество требуемых вам индексов - 100. Вы же хотите, что бы каждый новы получал новый индекс, а старые имели null, что бы избежать смещение индексов. как результат максимальный предел Int32 это цветочки, по сравнению с коллекцией в которой 10000 объектов имеют значение null, а всего 100 используются.

    Индекс в коллекции не самый удачный способ идентифицировать объект. Куда проще использовать свою индексацию и писать ID объекта в его свойство Tag. По свойству Tag находим объект в коллекции и работаем с ним. Так у вас всегда будет только те объекты, что вам нужны и их можно легко идентифицировать.


    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    19 июня 2012 г. 15:42
    Отвечающий
  • График у меня скроллируемый. Канву, на которой он рисуется, я поместил в экземпляр класса ScrollViewer и свойство Width канвы у меня периодически наращивается. Мне нужно отобразить свечи за всю сессию. Что касается null, то я хочу его присваивать не старым свечам, а вот как. Например, начался 1-минутный интервал времени для сбора данных для отрисовки очередной свечи. Я получил первую котировку по выбранному для торговли инструменту и отрисовал её. Т.к. в этом случае, точка открытия позиции равна точке её закрытия, то отрисовывается горизонтальный отрезок прямой, представляющий тело свечи (я пока не говорю о тени). Затем, я получаю очередную новую котировку, которые трактую как данные закрытия позиции. Положим, её значение отличается от предыдущего, которое я в течении всей минуты держу как данные открытия позиции, и в этом случае я перерисовываю тело свечи как прямоугольник. Но т.к. я могу иметь доступ по индексу на канве, то я не хочу удалив отрезок прямой получить ещё один индекс установкой на канву прямоугольника, а хочу прямоугольник воткнуть по освободившемуся индексу отрезка. Но что бы удалить отрезок, мне надо сделать либо RemoveAt(), либо присвоить null. Вот зачем мне null ! А когда свеча отрисована, то индексы прямоугольника и прямой-тени, составляющих её - остаются. Я по ним её двигаю влево. А на счёт использования ID объекта - замечание дельное. Правда я в первый раз пишу приложение для фондового рынка и в WPF пока не очень силён.

    P.S. Даже если я буду пока использовать индексы на канве и в течении каждой минуты, во время построения свечи (при изменении формы её тела), по несколько раз получать новый индекс, то и тогда вряд ли я превышу максимальное значение для Int32.



    • Изменено TownSparrow 19 июня 2012 г. 18:28
    19 июня 2012 г. 18:14
  • Становится трудно когда топик начат с одного вопроса, а продолжается по другому, поэтому давайте сначала - сейчас в рамках вопросов, поднятых в этом топике, что у вас не получается и в чем вам нужно подсказать?

    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    20 июня 2012 г. 3:06
    Отвечающий
  • Вынужден продолжить тему.

    • Изменено TownSparrow 21 июня 2012 г. 12:01
    20 июня 2012 г. 5:29
  • Так что бы продолжить тему нужно понять что у вас не получается или какой вопрос остался без ответа.

    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    21 июня 2012 г. 12:09
    Отвечающий
  • При попытке присвоить null по индексу, по которому уже находится элемент на WPF-канве появляется исключение: ArgumentNullException: Значение не может быть неопределенным. Ожидается объект, производный от UIElement. Т.е.

    this.ChartCanvas.Children.Add(myLine);

    int myIndex = this.ChartCanvas.Children.IndexOf(myLine);

    this.ChartCanvas.Children[myIndex] = null; // Здесь возникает вышеописанное исключение.

    Может можно как-нибудь сначала отсоединить дочерний элемент Visual, соответствующий указанному индексу, а потом на этот же индекс записать другой элемент? Помогите, пожалуйста.

    P.S. RemoveAt() мне делать нельзя. Мне нужно что бы у меня индексы не плыли, а сохранялась их последовательность.



    • Изменено TownSparrow 21 июня 2012 г. 12:17
    21 июня 2012 г. 12:13
  • ChartCanvas.Children.RemoveAt(myIndex);
    ChartCanvas.Children.Insert(myIndex, myRect);

    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    А вот этот вот мой ответ не является ответом на ваш вопрос? Вы сначала удаляете объект с индексом Х а потом вставляете в это же место новый. А что решение с идентификацией объектов по свойству Tag, а не по индексу в коллекции вам не нравится?

    Индексы не поплывут если эти 2 строки будут выполнятся друг за другом.


    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    • Изменено LXGDARKEditor 21 июня 2012 г. 12:17
    • Помечено в качестве ответа TownSparrow 21 июня 2012 г. 18:09
    21 июня 2012 г. 12:16
    Отвечающий
  • Да мне оно нравится, да время уже поджимает, а у меня много на этих индексах завязано. А в случае

    ChartCanvas.Children.RemoveAt(myIndex);
    ChartCanvas.Children.Insert(myIndex, myRect);

    индексы не поплывут? Ой, LXGDARK, извините, пожалуйста, я сейчас как на иголках и не заметил этой вашей строки

    "Индексы не поплывут если эти 2 строки будут выполнятся друг за другом."

    Извините, ради Бога.

    • Изменено TownSparrow 21 июня 2012 г. 12:28
    21 июня 2012 г. 12:24
  • Надеюсь вас не оскорбит моя попытка объяснить понятие индекса в коллекции как можно проще.

    Итак у нас есть 10 карандашей. Мы считаем их слева на право. Если мы уберем со стола карандаш номер 5, то когда начнем считать снова тот что был 6-м, станет 5-м, 7-й - 6-м и т.д. НО, если мы сразу же, до того как начнем считать снова на то место положим фломастер, то 5-м будет фломастер, что был 6-м, 6-м так и останется. Таким образом если удаление из коллекции объекта и помещение нового объекта делать до вызова IndexOf, индексы сохранятся у всех объектов. Что возвращает меня к утверждению "Индексы не поплывут если эти 2 строки будут выполнятся друг за другом."


    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    21 июня 2012 г. 12:29
    Отвечающий
  • Спасибо БОЛЬШОЕ. Сейчас потраю этот код.

    Потраил - вроде работает. Сейчас на долгий отрезок времени - минут на 30 запущу приложение, посмотрю как свечи отрисовываться будут. У меня все на этих индексах завязано - и разметка и изменение масштабной сетки и свечи. Когда начинал, то к сожалению упустил из внимания свойство Tag. А свойство действительно полезное, ведь в него, как я понимаю, можно не просто числовой идентификатор сунуть, а целый класс или структуру (в смысле - объект класса или структуры).

    • Изменено TownSparrow 21 июня 2012 г. 12:48
    21 июня 2012 г. 12:34