Click here to Skip to main content
15,914,111 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
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?


What I have tried:

Dialog window:
<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>

View Model:
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);
            }
        }
    }
}

Collection of XML files
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 element
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() { }
    }
}
Posted
Updated 13-Oct-20 1:28am

1 solution

Quote:
C#
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);
    }
}
When the selected file changes, you raise the "property changed" event for the SelectedFile property, but you never raise the event for the PipesFromSelectedFile property.

Try changing the LoadFromXmlFile method to use the property instead:
C#
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;
}
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900