none
Сериализация значений WPF PropertyGrid RRS feed

  • Вопрос

  • Есть два PropertyGrid в каждом из котором значения определенного класса. 

    Первый PropertyGrid имеет значения класса Tube, который в свою очередь имеет наследников, второй PropertyGrid имеет значения класса Intersection, котоый тоже имеет наследников. Необходимо сохранить оба PropertyGrid в один XML файл. Делаю так:

    private Type tube = typeof(Tube);
            private Type[] intersection = { typeof(Intersection)};
    
    public bool SaveXml(Tube m_tube, Intersection m_intersecion, string m_fileName)
            {
                FileStream fs = new FileStream(m_fileName, FileMode.Create);
    
                XmlSerializer serializer = new XmlSerializer(this.tube, this.intersection);
    
                serializer.Serialize(fs, m_tube);
                fs.Close();
    
                return true;
            }

    но сохраняются значения только одно класса, а нужно что бы двух классов.

    При попытке сделать так:

            public bool SaveXml(Tube m_tube, Intersection m_intersection, string m_fileName)
            {
    
                using (StreamWriter writer = new StreamWriter(m_fileName))
                {
                    try
                    {
                        XmlSerializer serializer = new XmlSerializer(typeof(Tube));
                        serializer.Serialize(writer, m_tube);
                        serializer.Serialize(writer, m_intersection);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                    finally
                    {
                        writer.Flush();
                        writer.Close();
                    }
                }
                return true;
            }

    выскакивает ошибка. Вариант с дополнительным классом, в котором нужно объявить эти два класса а потом сериализовывать не работает, так как при  вызове метода для сохранения нужно обязательно указать именно эти два класса. Возможно есть какое нибудь решение, или может быть кто то уже сталкивался с таким случаем? Использую WPF PropertyGrid.



    • Изменено nigina_1989 26 ноября 2012 г. 11:10
    26 ноября 2012 г. 11:08

Ответы

  • Да вы записывает 2 файла в пакет, а потом при необходимости извлекаете потоки файлов и десериализуете в классы.

    На странице описания Package есть пример. Разбирайтесь и спрашивайте что именно не понятно. В вашем случае упаковки это самое удобное решение.


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

    • Помечено в качестве ответа nigina_1989 27 ноября 2012 г. 12:10
    26 ноября 2012 г. 14:24
    Отвечающий
  • Хмм... Предложу такое решение.

    Tube tube = ...
    Intersection intersection = ...
    
    // Записываем два разных объекта в один файл
    var settings = new XmlWriterSettings { Indent = true };
    using (var writer = XmlWriter.Create("test.xml", settings))
    {
        // Вручную создаём корневой элемент
        writer.WriteStartElement("root");
    
        var ser = new XmlSerializer(typeof(Tube));
        ser.Serialize(writer, tube);
    
        ser = new XmlSerializer(typeof(Intersection));
        ser.Serialize(writer, intersection);
    
        writer.WriteEndElement();
    }
    
    // Читаем из одного файла два разных объекта
    using (var reader = XmlReader.Create("test.xml"))
    {
        // Вручную смещаемся до нужного класса
        reader.ReadToFollowing("Tube");
    
        var ser = new XmlSerializer(typeof(Tube));
        tube = (Tube)ser.Deserialize(reader);
    
        ser = new XmlSerializer(typeof(Intersection));
        intersection = (Intersection)ser.Deserialize(reader);
    }

    • Помечено в качестве ответа nigina_1989 27 ноября 2012 г. 12:10
    26 ноября 2012 г. 17:14

Все ответы

  • Не совсем пойму, почему не работает вариант с объединяющим классом? Если оба класса сериализуемы и они объявлены как поля третьего класса, то сериализация его должна пройти без проблем. Или объясните подробнее почему это не прокатывает.


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

    26 ноября 2012 г. 12:33
    Отвечающий
  • Объявление и подключение класса Tube для PropertyGrid объявлены в этом классе:

    namespace Prototyp1_1.GUI.ViewModel { public class PartViewModel : ViewModelBase { private Tube m_tube; private TubeType m_tubeType; public PartViewModel() { m_tubeType = TubeType.Not_Specified; SetTubeTypes(); }

    public TubeType _TubeType { get { return m_tubeType; } set { if (value == m_tubeType) return; m_tubeType = value; OnTubeTypeChanged(); base.OnPropertyChanged("_TubeType"); } }

    public List<TubeType> TubeTypes { get; set; } public Tube _Tube { get { return m_tube; } set { m_tube = value; base.OnPropertyChanged("_Tube"); } } public void OnTubeTypeChanged() { switch (m_tubeType) { case TubeType.BentTube: _Tube = new BentTube(); break; case TubeType.Dome: _Tube = new Dome(); break; case TubeType.OvalTube: _Tube = new OvalTube(); break; case TubeType.RectangularTube: _Tube = new RectangularTube(); break; case TubeType.RoundTube: _Tube = new RoundTube(); break; } MainViewModel.GetInstance().IntersectionToolbar._TubeType = m_tubeType; }

    private void SetTubeTypes() { Array values = Enum.GetValues((typeof(TubeType))); TubeTypes = new List<TubeType>(); foreach (TubeType value in values) { TubeTypes.Add(value); } TubeTypes.Remove(TubeType.Not_Specified); } } }

    Соответственно для PropertyGrid Intersection следующий класс:

    namespace Prototyp1_1.GUI.ViewModel { public class IntersectionViewModel : ViewModelBase { Intersection _intersection; IntersectionRepository _intersectionRepository; ObservableCollection<CommandViewModel> _intersections; ICollectionView _intersectionView; bool _isSelected; public IntersectionViewModel() { _intersectionRepository = new IntersectionRepository(); _intersectionView = CollectionViewSource.GetDefaultView(_intersectionRepository._Intersections); _IntersectionView.CurrentChanged += IntersectionSelectionChanged; } public IntersectionViewModel(Intersection intersection, IntersectionRepository intersectionRepository) { if (intersection == null) throw new ArgumentNullException("intersection"); if (intersectionRepository == null) throw new ArgumentNullException("intersectionRepository");

    _intersection = intersection; _intersectionRepository = intersectionRepository; }

    public bool IsSelected { get { return _isSelected; } set { if (value == _isSelected) return; _isSelected = value; base.OnPropertyChanged("IsSelected"); } } public Intersection _Intersection { get { return _intersection; } set { if (value == null) return; _intersection = value; OnPropertyChanged("_Intersection"); } } public IntersectionType _IntersectionType { get { return _intersection._IntersectionType; } set { if (value == _intersection._IntersectionType) return; _intersection._IntersectionType = value; base.OnPropertyChanged("Intersection"); } } public IntersectionRepository _IntersectionRepository { get { return _intersectionRepository; } } public ICollectionView _IntersectionView { get { return _intersectionView; } }

    public ObservableCollection<CommandViewModel> _Intersections { set { _intersections = value; base.OnPropertyChanged("Commands"); } get { if (_intersections == null) { _intersections = new ObservableCollection<CommandViewModel>(); } return _intersections; } }

    public void addIntersectionListItem(IntersectionListItem intersection) { _Intersection = intersection._Intersection; _IntersectionRepository.AddIntersection(intersection); _IntersectionView.Refresh(); // update the view } public void onIntersectionClicked() { object o = _IntersectionView.CurrentItem; }

    void IntersectionSelectionChanged(object sender, EventArgs e) { IntersectionListItem i = (IntersectionListItem)_IntersectionView.CurrentItem; if(i != null) _Intersection = i._Intersection; } } }

    Т.е. при сохранение в методе должны быть указаны не просто два класса Tube и Intersection а такие классы как: PartViewModel и IntersectionViewModel. Вызов метода для сохранения:

    public class MainViewModel : ViewModelBase { IntersectionToolbarViewModel m_intersectionToolbar; PartViewModel m_partView; string _projectFolder;

    private static MainViewModel instance = null; public MainViewModel() { base.DisplayName = Strings.MainViewModel_DisplayName; _projectFolder = ""; } public static MainViewModel GetInstance() { if (instance == null) { instance = new MainViewModel(); } return instance; } List<CommandViewModel> CreateCommands() { return new List<CommandViewModel> { new CommandViewModel( LocalizedStrings.Instance.getLocalizedCommands("MainViewModel_Command_Save"), new ActionCommand(param => this.Save())), }; }

    public PartViewModel PartView { get { if (m_partView == null) { m_partView = new PartViewModel(); } return m_partView; } }

    public IntersectionViewModel IntersectionView { get { if (m_intersectionView == null) { m_intersectionView = new IntersectionViewModel(); } return m_intersectionView; } } void Save() { PartSerializer part = new PartSerializer(); Microsoft.Win32.SaveFileDialog saveDialog = new Microsoft.Win32.SaveFileDialog(); saveDialog.InitialDirectory = @"C:\"; saveDialog.Filter = "Text documents (.xml)|*.xml"; if (saveDialog.ShowDialog() == true) { _projectFolder = saveDialog.FileName; part.SaveXml(PartView._Tube, IntersectionView._Intersection, saveDialog.FileName); } } }

    Поэтому вариант с объединяющим классом не подходит.

    • Изменено nigina_1989 26 ноября 2012 г. 13:10
    26 ноября 2012 г. 12:52
  • Не думаю, что получится создать один xml с двумя классами, так как формат xml требует наличие одного корневого элемента.

    А в чем цель? Что бы был один физический файл? Если так, то можно упаковать 2 xml в один файл.


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

    26 ноября 2012 г. 13:32
    Отвечающий
  • Да нужно что бы создался один файл, в котором будут хранится значения двух PropertyGrid. А если применить упаковку, то как тогда читать этот файл? Снова его распоковывать и читать каждый файл по отдельности? Или как? Я ещё не разу не пользовалась упаковкой.
    • Изменено nigina_1989 26 ноября 2012 г. 14:21
    26 ноября 2012 г. 14:20
  • Да вы записывает 2 файла в пакет, а потом при необходимости извлекаете потоки файлов и десериализуете в классы.

    На странице описания Package есть пример. Разбирайтесь и спрашивайте что именно не понятно. В вашем случае упаковки это самое удобное решение.


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

    • Помечено в качестве ответа nigina_1989 27 ноября 2012 г. 12:10
    26 ноября 2012 г. 14:24
    Отвечающий
  • Спасибо за совет буду разбираться. А  как тогда при сохранении создать два xml файла для каждого PropertyGrid одновременно? Я с таким ещё не разу не сталкивалась.
    26 ноября 2012 г. 15:03
  • Хмм... Предложу такое решение.

    Tube tube = ...
    Intersection intersection = ...
    
    // Записываем два разных объекта в один файл
    var settings = new XmlWriterSettings { Indent = true };
    using (var writer = XmlWriter.Create("test.xml", settings))
    {
        // Вручную создаём корневой элемент
        writer.WriteStartElement("root");
    
        var ser = new XmlSerializer(typeof(Tube));
        ser.Serialize(writer, tube);
    
        ser = new XmlSerializer(typeof(Intersection));
        ser.Serialize(writer, intersection);
    
        writer.WriteEndElement();
    }
    
    // Читаем из одного файла два разных объекта
    using (var reader = XmlReader.Create("test.xml"))
    {
        // Вручную смещаемся до нужного класса
        reader.ReadToFollowing("Tube");
    
        var ser = new XmlSerializer(typeof(Tube));
        tube = (Tube)ser.Deserialize(reader);
    
        ser = new XmlSerializer(typeof(Intersection));
        intersection = (Intersection)ser.Deserialize(reader);
    }

    • Помечено в качестве ответа nigina_1989 27 ноября 2012 г. 12:10
    26 ноября 2012 г. 17:14
  • Спасибо LXGDARK буду разбираться с упаковкой, возникнут вопросы создам отдельную тему.

    Petalvik спасибо за ваш вариант он работает.

    27 ноября 2012 г. 12:15