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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Сохранить коллекцию TreeViewItems, или клонировать или не клонировать 
V
    Опции темы
Тигер
Дата 23.7.2013, 06:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Здравствуйте, такая задач: Нужно сохранить CollectionItems (или IEnumerate ItemsSource) чтобы потом, восстановить значения в TreeView.
Тоесть обычно для этого понадобилось бы клонировать объект коллекции, однако в C# нет нативных методов для клонирования, а значит разработчики C# считаю эту операцию костыльной. 
Следовательно для решения данной задачи должен быть более оптимальный способ.
Спасибо!
PM MAIL   Вверх
dzaraev
Дата 23.7.2013, 07:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Во-первых нативные методы есть и клонирование - совсем не костыльная операция сама по себе.
Вот что есть из коробки (на вскидку):
Object.MemberwiseClone - метод
ICloneable - интерфейс

А во-вторых - в чем проблема просто сохранить ссылку на значение ItemSource?
--------------------
Если вопрос решён - помечайте тему.  
PM MAIL   Вверх
Тигер
Дата 23.7.2013, 20:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Ну интерфейс - это же не нативная поддержка? MemberwiseClone() не реализован в коллекции итемов, или я просто не там искал.
Цитата

А во-вторых - в чем проблема просто сохранить ссылку на значение ItemSource?

Не совсем понял, а как я буду восстанавливать старые значения дерева из этой ссылки?
Ещё раз, что я хочу сделать:
Код

oldItems=clone TreeView.ItemsSource;
/* some code */
TreeView.Items.Clear();
TreeView.ItemsSource=oldItems;


тоесть если нет clone, значит это должно делаться как-то по-другому (разумеется это можно сделать написав обертку наж коллекцией или может быть пройтись в цикле по элементам, но все это выглядит как-то костыльно)

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


Шустрый
*


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

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



вот что предлагают на стековерфлоу
Код

public static T DeepTreeCopy<T>(T obj)
    {
        object result = null;
        using (var ms = new MemoryStream())
        {
            var formatter = new BinaryFormatter();
            formatter.Serialize(ms, obj);
            ms.Position = 0;
            result = (T)formatter.Deserialize(ms); ms.Close();
        }
        return (T)result;
    } 

жесть имхо )
PM MAIL   Вверх
dzaraev
Дата 24.7.2013, 06:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Давайте по-порядку:
Цитата(Тигер @  23.7.2013,  20:21 Найти цитируемый пост)
Ну интерфейс - это же не нативная поддержка? MemberwiseClone() не реализован в коллекции итемов, или я просто не там искал.

Вы читали про метод MemberwiseClone ? Мне кажется что нет, хотя я даже ссылку вам оставил. Этот метод создаёт shallow-копию объекта и реализован в единственном виде в классе Object. Интерфейс ICloneable это еще какая поддержка, но для интерфейса нужна реализация, которой может стать например MemberwiseClone. 
Вот пример использования:
Код

    public class Class1 : ICloneable
    {
        private string _field1;
        private double _field2;

        public Class1(string field1, double field2)
        {
            _field1 = field1;
            _field2 = field2;
        }

        public int Prop1 { get; set; }

        public object Clone()
        {
            return MemberwiseClone();
        }
    }

public static void Main()
{
    Class1 original = new Class1("helloworld", 3.14) {Prop1 = 100500};
    Class1 clone = (Class1) original.Clone();
    //теперь переменная clone содержит те же данные, что и original
}




Цитата(Тигер @  23.7.2013,  20:21 Найти цитируемый пост)
Цитата

А во-вторых - в чем проблема просто сохранить ссылку на значение ItemSource?

Не совсем понял, а как я буду восстанавливать старые значения дерева из этой ссылки?
Ещё раз, что я хочу сделать:

Код

oldItems=clone TreeView.ItemsSource;
/* some code */
TreeView.Items.Clear();
TreeView.ItemsSource=oldItems;


Каков был вопрос, таков и ответ. Вы не пояснили - что именно имеется в виду под "сохранять" и "восстанавливать".
Если вам нужно сохранить данные куда-то на диск, или передать по сети, то вам нужна сериализация (это ссылка).
Если же вам нужно просто на время подменить дереву элементы, а потом вернуть предыдущий набор, то достаточно просто сохранить указатель на значение ItemsSource, как я и предложил.
Далее, ваш пример кода - во-первых  он показывает, что ваша старая коллекция никуда не сохраняется, а просто болтается в памяти, и зачем тут нужен clone,  я не понимаю. Во-вторых, допускаете грубую ошибку - TreeView наследуется от класса ItemsControl, и вот что говорится про этот класс и его свойства Items и ItemsSource:
Цитата(MSDN)

Обратите внимание, что используется либо Items, либо свойство ItemsSource чтобы указать коллекцию, которая должна использоваться для создания содержимого конкретного ItemsControl. Если задано свойство ItemsSource, коллекция Items выполнена только для чтения и фиксированным размером.

Короче говоря, если вы до вызова Items.Clear устанавливали ItemsSource (а вы устанавливали, раз пытаетесь его клонировать), то ваш код
Код

TreeView.Items.Clear();

Вызовет исключение InvalidOperationException.
Нужно либо работать с ItemsSource и с коллекцией, на которую это свойство указывает, либо с коллекцией Items. В случае работы с ItemsSource, если вы хотите очистить дерево от элементов, просто присвойте свойству ItemsSource - null.
Учитывая тот код, что вы написали под словами "что я хочу сделать" я полагаю, что именно временная подмена коллекции дерева и было вашей целью и тогда моё предложение в силе, вот так я предлагал сделать:
Код

            //Изначальная коллекция
            List<string> itemsSource = new List<string> { "one", "two", "three" };
            myTreeView.ItemsSource = itemsSource;

            //новая коллекция
            List<string> anotherItemsSource = new List<string> { "tra", "ta", "tarara" };
            
            //сохраняем ссылку на старую коллекцию
            IEnumerable oldItemsSource = myTreeView.ItemsSource;

            //подключаем новую к дереву
            myTreeView.ItemsSource = anotherItemsSource;
            //потом нам вздумалось очистить дерево
            myTreeView.ItemsSource = null;

            //теперь решили вернуть старую коллекцию
            myTreeView.ItemsSource = oldItemsSource;


Далее:
Цитата(Тигер @  23.7.2013,  22:54 Найти цитируемый пост)
вот что предлагают на стековерфлоу
Код

public static T DeepTreeCopy<T>(T obj)
    {
        object result = null;
        using (var ms = new MemoryStream())
        {
            var formatter = new BinaryFormatter();
            formatter.Serialize(ms, obj);
            ms.Position = 0;
            result = (T)formatter.Deserialize(ms); ms.Close();
        }
        return (T)result;
    } 

жесть имхо ) 

Это не жесть, это вам предложили клонирование через сериализацию (о которой я упоминал выше). Это самый медленный способ клонирования и я его не советую. Если вас все-таки интересует глубокое клонирование данных, вот тут хороший ответ с подборкой вариантов клонирования, возможных в C#.


--------------------
Если вопрос решён - помечайте тему.  
PM MAIL   Вверх
Тигер
Дата 24.7.2013, 10:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Спасибо за подробный ответ!

Под нативной поддержкой, я имел ввиду языковые конструкции. Про MemberwiseClone() я читал ещё до начала топика, про интерфейс после ) Но под мою задачаю они не подходят, потому что интерфейс не реализует коллекция, а MemberwiseClone() protected.

Идею вашу я понял, единственной, я изначально работаю с .Items (которео readonly, поэтому и решил для "восстановления" старых значений использовать ItemsSource) Вобщем, я не совсем понимаю как портировать ваш код
Ещё раз, что хотелось бы получить
Код

                var treeview = new TreeView();
                var item = new TreeViewItem() { Header="t0"};
                item.Items.Add(new TreeViewItem() { Header="t00"});
                treeview.Items.Add(item);

                var oldItems = treeview.Items;   // вот тут по идее и нужно клонирование
                /*some code with change treeview*/
                treeview.Items.Clear();
                treeview.Items = oldItems; // Восстановили структуру


Ещё я пробовал так:
Код

 object[] oldItems;
 oldItems=new object[infoBox_treeview.Items.Count];
 treeview.Items.CopyTo(oldItems, 0);
 /*какие-то изменения treeview*/
 treeview.Items.Clear();
 treeview.ItemsSource=oldItems.AsEnumerable();

такой вариант работал, только вот oldItems содержало не копии Item'ом, а ссылки на них...

Это сообщение отредактировал(а) Тигер - 24.7.2013, 11:00
PM MAIL   Вверх
dzaraev
Дата 24.7.2013, 15:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(Тигер @  24.7.2013,  10:41 Найти цитируемый пост)
 я изначально работаю с .Items (которео readonly, поэтому и решил для "восстановления" старых значений использовать ItemsSource) 

Это конечно неправильно.

Цитата(Тигер @  24.7.2013,  10:41 Найти цитируемый пост)
 Вобщем, я не совсем понимаю как портировать ваш код

Ну если вы изначально работаете с Items,  то уже никуда не "портируете" конечно, у меня используется ItemsSource.


Цитата(Тигер @  24.7.2013,  10:41 Найти цитируемый пост)
Ещё раз, что хотелось бы получить
Код

                var treeview = new TreeView();
                var item = new TreeViewItem() { Header="t0"};
                item.Items.Add(new TreeViewItem() { Header="t00"});
                treeview.Items.Add(item);
                var oldItems = treeview.Items;   // вот тут по идее и нужно клонирование
                /*some code with change treeview*/
                treeview.Items.Clear();
                treeview.Items = oldItems; // Восстановили структуру

C Items конечно такое не прокатит, т.к. вы сами убедились - это свойство только для чтения.

Цитата(Тигер @  24.7.2013,  10:41 Найти цитируемый пост)
Ещё я пробовал так:
Код

 object[] oldItems;
 oldItems=new object[infoBox_treeview.Items.Count];
 treeview.Items.CopyTo(oldItems, 0);
 /*какие-то изменения treeview*/
 treeview.Items.Clear();
 treeview.ItemsSource=oldItems.AsEnumerable();

такой вариант работал, только вот oldItems содержало не копии Item'ом, а ссылки на них...

Конечно ссылки, потому что метод CopyTo просто копирует элементы, т.е. ссылки на них - в ваш массив. О клонировании речи и не идёт.
Причем я бы заменил последнюю строчку на заполнение массива Items старыми значениеям, раз уж вы изначально работаете с Items.
И тут сразу вопрос - вам точно нужны именно клоны старых элементов? Просто старые ссылки, которые возвращаются на своё место - не подходят, как решение?
Если не подходит, то дальше варианта я вижу два 
- Самостоятельно реализовать клонирование TreeViewItem одним из способов (про способы - пост выше)
- Реализовать клонирование данных, которые помещаются в ваши TreeViewItem и при "сохранении" - клонировать именно данные, а не сами элементы TreeViewItem. Сами же элементы TreeViewItem могут настраиваться при помощи шаблона DataTemplate, стилей и т.д. и т.п.
Второй вариант - самый адекватный. Практическую необходимость первого же варианта я представляю с трудом.
--------------------
Если вопрос решён - помечайте тему.  
PM MAIL   Вверх
Тигер
Дата 24.7.2013, 16:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата

Просто старые ссылки, которые возвращаются на своё место - не подходят, как решение?

Ну если я правильно понимаю что имеется ввиду под старыми ссылками, то я так и решил сделать. т.е. программным путем удаляю некоторые Items и тп.
Данные клонировать так же не получится, тк. у меня в качестве данных используются объекты (контролы). Разве что писать обертку и уже её помещать в качестве данных в Items...
Спасибо!

Это сообщение отредактировал(а) Тигер - 24.7.2013, 16:33
PM MAIL   Вверх
dzaraev
Дата 24.7.2013, 20:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(Тигер @  24.7.2013,  16:32 Найти цитируемый пост)
Ну если я правильно понимаю что имеется ввиду под старыми ссылками, то я так и решил сделать.

"Старые ссылки" - это просто ссылки на ваши старые элементы коллекции, которые были в коллекции изначально - вот что я имел ввиду.

Цитата(Тигер @  24.7.2013,  16:32 Найти цитируемый пост)
Разве что писать обертку и уже её помещать в качестве данных в Items...
Спасибо!

Если вопрос решён, пометьте его как рашённый пожалуйста  smile 
--------------------
Если вопрос решён - помечайте тему.  
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

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


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

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


 




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


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

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