Dion Alexander Ответов: 1

Как обновить список WPF с элементами выбранного XML-файла


I have a WFP window that contains a ComboBox that is bound to a list of XML files and a ListBox that should display the elements of the selected XML file in the Combox. The TextBlock between the ComboBox and the ListBox is used to demonstrate that the binding to the selected value works. However, the ListBox displays the elements of the first XML file but does not update when the selection changes.

The code is included below. What have I done wrong and what am I missing?


Что я уже пробовал:

Диалоговое окно:
<Window x:Class="ReinforcementPlates.Views.SteelPipesDialog"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:Views="clr-namespace:ReinforcementPlates.Views"
        mc:Ignorable="d"
        Title="Steel Pipe Catalogue" Height="400" Width="400"
    DataContext="{Binding ViewModel, RelativeSource={RelativeSource Self}}">
    <Grid Margin="5">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="95*"/>
            <RowDefinition Height="15*"/>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" Margin="2">
            <Label>Select a catalogue:</Label>
            <ComboBox ItemsSource="{Binding Files, Mode=OneWay}" DisplayMemberPath="Name" SelectedValue="{Binding SelectedFile}" SelectedValuePath="Name" Width="240" Height="20" Margin="0,3" IsSynchronizedWithCurrentItem="True"/>
        </StackPanel>
        <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="2">
            <TextBlock Text="Selected catalog:" Margin="0,0,3,0"/>
            <TextBlock Text="{Binding SelectedFile}" Margin="3,0,0,0"/>
        </StackPanel>
        <ListBox Grid.Row="2" HorizontalAlignment="Center" ItemsSource="{Binding PipesFromSelectedFile, UpdateSourceTrigger=PropertyChanged}" Margin="2" IsSynchronizedWithCurrentItem="True">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="50"/>
                            <ColumnDefinition Width="60"/>
                            <ColumnDefinition Width="60"/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Grid.Column="0" Text="{Binding Bore}"/>
                        <TextBlock Grid.Column="1" Text="{Binding OutsideDiameter}"/>
                        <TextBlock Grid.Column="2" Text="{Binding WallThickness}"/>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <StackPanel Grid.Row="3" Grid.ColumnSpan="3" Orientation="Horizontal" HorizontalAlignment="Center">
            <Button IsDefault="True" Height="20" MinWidth="75" Margin="10" Padding="1" Click="Accept_Button">Accept</Button>
            <Button IsCancel="True" Height="20" MinWidth="75" Margin="10" Padding="1" Click="Cancel_Button">Cancel</Button>
        </StackPanel>
    </Grid>
</Window>

модель представления:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using ReinforcementPlates.SteelPipeCatalogs;
using System.IO;
using System.Xml.Serialization;

namespace ReinforcementPlates.ViewModels {
     public class SteelPipesDialogViewModel : BaseViewModel {
        private string dir = @".\SteelPipeCatalogs";
        private DirectoryInfo catalogDirectory;
        private string selectedFile;
        private readonly List<FileInfo> catalogFiles = new List<FileInfo>();
        private ObservableCollection<SteelPipeSize> pipesFromSelectedFile;

        public SteelPipesDialogViewModel() {
            catalogDirectory = new DirectoryInfo(dir);
            catalogFiles.AddRange(catalogDirectory.GetFiles("*.xml"));
        }

        public List<FileInfo> Files {
            get { return catalogFiles; }
        }


        public string SelectedFile {
            get { return selectedFile; }
            set {
                if (selectedFile != value) {
                    selectedFile = value;
                    OnPropertyChanged(nameof(SelectedFile));
                    LoadFromXmlFile(selectedFile);
                }
            }
        }

        public ObservableCollection<SteelPipeSize> PipesFromSelectedFile {
            get { return pipesFromSelectedFile; }
            set {
                if (pipesFromSelectedFile != null) {
                    pipesFromSelectedFile = value;
                    OnPropertyChanged(nameof(PipesFromSelectedFile));
                }
            }
        }

        private void LoadFromXmlFile(string selectedFile) {
            SteelPipeSizeList pipes = new SteelPipeSizeList();
            string fileName = Path.Combine(dir, selectedFile);
            XmlSerializer serializer = new XmlSerializer(typeof(SteelPipeSizeList));

            using (FileStream fStream = File.OpenRead(fileName)) {
                pipes = serializer.Deserialize(fStream) as SteelPipeSizeList;
            }

            pipesFromSelectedFile = new ObservableCollection<SteelPipeSize>();
            foreach (var pipe in pipes.SteelPipes) {
                pipesFromSelectedFile.Add(pipe);
            }
        }
    }
}

Коллекция XML-файлов
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using ReinforcementPlates.Models;

namespace ReinforcementPlates.SteelPipeCatalogs {
    [XmlRoot("SteelPipeSizeList")]
    public class SteelPipeSizeList {

        public SteelPipeSizeList() {
            SteelPipes = new List<SteelPipeSize>();
        }

        [XmlArray("SteelPipeSizes")]
        [XmlArrayItem("SteelPipeSize", typeof(SteelPipeSize))]
        public List<SteelPipeSize> SteelPipes { get; set; }

        public void AddPipeSize(SteelPipeSize size) {
            SteelPipes.Add(size);
        }
    }
}

XML-элемент
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ReinforcementPlates.SteelPipeCatalogs {
    [Serializable]
    public class SteelPipeSize {
        public double Bore { get; set; }
        public double OutsideDiameter { get; set; }
        public double WallThickness { get; set; }

        public SteelPipeSize() { }
    }
}

1 Ответов

Рейтинг:
1

Richard Deeming

Цитата:
public string SelectedFile {
    ...
    set {
        if (selectedFile != value) {
            selectedFile = value;
            OnPropertyChanged(nameof(SelectedFile));
            LoadFromXmlFile(selectedFile);
        }
    }
}
...
private void LoadFromXmlFile(string selectedFile) {
    ...
    pipesFromSelectedFile = new ObservableCollection<SteelPipeSize>();
    foreach (var pipe in pipes.SteelPipes) {
        pipesFromSelectedFile.Add(pipe);
    }
}
Когда выбранный файл изменяется, вы вызываете событие "свойство изменено" для SelectedFile собственность, но вы никогда не поднимаете событие для PipesFromSelectedFile собственность.

Попробуйте изменить LoadFromXmlFile способ использования этого свойства вместо него:
private void LoadFromXmlFile(string selectedFile) {
    ...
    
    // Store the pipes in a local variable instead of the field:
    var pipesFromSelectedFile = new ObservableCollection<SteelPipeSize>();
    foreach (var pipe in pipes.SteelPipes) {
        pipesFromSelectedFile.Add(pipe);
    }
    
    // Set the property instead of the field, so that the changed event fires:
    PipesFromSelectedFile = pipesFromSelectedFile;
}