bergermeister
bergermeister

Reputation: 164

WPF: What's the proper way to do nested Binding

I have 3 models: Machine, Part, and Component. On my ui, I have bound one listbox to a list of Machines and a second listbox to the selected Machine's list of Parts. Now when the user selects a part, I would like to bind a datagrid to the selected part's list of components. I tried setting the datagrid's itemssource to:

ItemsSource="{Binding ElementName=PartSelectList, Path=SelectedItem.Components}"

I also tried setting its datacontext and itemssource

DataContext={Binding ElementName=PartSelectList, Path=SelectedItem}

ItemsSource={Binding Components}

However the datagrid does not automatically update if changes are made to the part's list of components via methods such as

part.Bags.Add(new Component(..));

Anyone have suggestions on how I should approach this?

Update: I have a class MachineCollection which implements INotifyPropertyChanged. In my xaml.cs code I create my MachineCollection object and bind the MainGrid to it's Machines property:

Page1.xaml.cs:

private MachineCollection machines

public Page1()
{
    machineCollection = new MachineCollection();
    MainGrid.DataContext = machineCollection.Machines 
    actionThread = new Thread(InitLists);
    actionThread.Start();
}

public void InitLists()
{
    machineCollection.Machines.AddRange(dbCon.GetAllMachines());
}

Classes:

public class MachineCollection : INotifyPropertyChanged
{
    public List<Machine> Machines
    {
        get { return machines; }
        set { machines = value; NotifyPropertyChanged("Machines"); }
    }
}

public class Machine : INotifyPropertyChanged
{
    public List<Part> Parts
    {
        get { return parts; }
        set { parts = value; NotifyPropertyChanged("Parts");
    }
}

public class Part : INotifyPropertyChanged
{
    public List<Component> Components
    {
        get { return components; }
        set { components = value; NotifyPropertyChanged("Components");
    }
}

public class Component : INotifyPropertyChanged
{
    public int Length
    {
        get { return length; }
        set { length = value; NotifyPropertyChanged("Length");
    }
}

XAML:

<Page>
<Grid Name="MainGrid">
    <ListBox x:Name="MachineSelectList" HorizontalAlignment="Left" VerticalAlignment="Bottom" 
                 Height="114"  Width="231"
                 Foreground="White" Background="#FF7A7A7A" FontSize="16" BorderBrush="#FFC13131"
                 ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid Width="200">
                        <TextBlock Text="{Binding SerialNumber}" TextAlignment="Left" HorizontalAlignment="Left" VerticalAlignment="Center"/>
                        <Button Name="DeleteMachine" Tag="{Binding SerialNumber}" HorizontalAlignment="Right" VerticalAlignment="Center" Height="20"
                                Background="{x:Null}" BorderBrush="{x:Null}" Foreground="{x:Null}" Focusable="False" Click="Btn_Click" >
                            <Image Source="..\Resources\Images\delete.png" Stretch="Uniform"/>
                        </Button>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

    <ListBox Name="PartSelectList" HorizontalAlignment="Left" VerticalAlignment="Bottom" 
                 Height="164"  Width="231"
                 Background="#FF7A7A7A" Foreground="White" FontSize="16" BorderBrush="#FFC13131"
                 ItemsSource="{Binding Path=Parts}" IsSynchronizedWithCurrentItem="True">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid Width="200">
                        <TextBlock Text="{Binding PartNumber}" TextAlignment="Left" HorizontalAlignment="Left" VerticalAlignment="Center"/>
                        <Button Name="DeletePart" Tag="{Binding PartNumber}" HorizontalAlignment="Right" VerticalAlignment="Center" Height="20"
                                Background="{x:Null}" BorderBrush="{x:Null}" Foreground="{x:Null}" Focusable="False" Click="Btn_Click" >
                            <Image Source="..\Resources\Images\delete.png" Stretch="Uniform"/>
                        </Button>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

</Grid>
</Page>

Upvotes: 1

Views: 318

Answers (1)

Daniel Castro
Daniel Castro

Reputation: 1290

One way to solve this is using ObservableCollection, which is made for situations like this.

public ObservableCollection<Part> Parts
{
    get { return parts; }
    set { parts = value; NotifyPropertyChanged("Parts");
}

Or you could implement the interface INotifyCollectionChanged manually

The problem is, basically, that the binding system does not know when you call Add. If you were reassigning the Parts property each time, then the system would just redraw everything, so it would reflect the changes too, but if ObservableCollection is not a problem, that's the prefered way

Upvotes: 1

Related Questions