WPF Binding to child of current item not updating

1.5k views Asked by At

I am currently binding to an ObservableCollection using an ICollectionView, myCollectionView. The contents of that collection are being selected from a ComboBox. Each collection item, myCollectionItem, has a VisualBrush, myVisualBrush, as a child and the CurrentItem's brush is displayed in a preview panel.

The collection item also a child object, myItemChild, which contains a number of its own properties that are used to generate a slider. This slider alters properties on the preview panel.

This all works as expected.

When the CurrentItem of the Collectionview is changed the preview panel updates correctly but the slider continues to show the previous CurrentItem's myItemChild.

The change to myItemChild is not being raised, how should I handle this situation?

Its highly probable I have missed something obvious so any pointers appreciated.

Regards

Rob

<Grid>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto"></RowDefinition>
    <RowDefinition Height="Auto"></RowDefinition>
    <RowDefinition Height="Auto"></RowDefinition>
  </Grid.RowDefinitions>

  <!-- Combo Box for selection of item-->
  <ComboBox Grid.Row="0" ItemsSource="{Binding myCollectionView, Mode=TwoWay}" IsSynchronizedWithCurrentItem="True">
    <ComboBox.ItemTemplate>
      <DataTemplate DataType="{x:Type vm:myCollectionItem}" >
        <StackPanel>
          <Rectangle Height="40" Width="40" Fill="{Binding myVisualBrush}"/>
        </StackPanel>
      </DataTemplate>
    </ComboBox.ItemTemplate>
  </ComboBox>

  <!-- Panel to preview item-->
  <ContentControl Grid.Row="1" Content="{Binding myCollectionView/}">
    <ContentControl.ContentTemplate>
      <DataTemplate DataType="{x:Type vm:myCollectionItem}" >
        <Rectangle Margin="20" Fill="{Binding myVisualBrush}" />
      </DataTemplate>
    </ContentControl.ContentTemplate>
  </ContentControl>

  <!-- Slider to edit item-->
  <ContentControl Grid.Row="2" Content="{Binding myCollectionView/}">
    <ContentControl.ContentTemplate>

      <DataTemplate DataType="{x:Type vm:myCollectionItem}" >
        <ContentControl Content="{Binding myItemChild}">
          <ContentControl.ContentTemplate>

            <DataTemplate DataType="{x:Type vm:myCollectionItemChild}" >
              <StackPanel>
                <Label Content="{Binding myValueLabel, Mode=OneWay}"/>
                <Slider Value="{Binding myValue, Mode=TwoWay}" Maximum="{Binding myValueMax}" Minimum="{Binding myValueMin}"/>
              </StackPanel>
            </DataTemplate>

          </ContentControl.ContentTemplate>
        </ContentControl>
      </DataTemplate>

    </ContentControl.ContentTemplate>
  </ContentControl>
</Grid>
1

There are 1 answers

1
vortexwolf On BEST ANSWER

I tried to reproduce your problem, but it works without problems. Here is my code-behind:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        var items = new ObservableCollection<myCollectionItem>{
            new myCollectionItem(Brushes.Red, new myCollectionItemChild("Red", 15, 0, 80)),
            new myCollectionItem(Brushes.Green, new myCollectionItemChild("Green", 0.7, 0, 1)),
            new myCollectionItem(Brushes.Purple, new myCollectionItemChild("Purple", 22,11,33))};
        this.DataContext = new Model { myCollectionView = items };
    }


}

public class Model
{
    public ObservableCollection<myCollectionItem> myCollectionView { get; set; }
}

public class myCollectionItem
{
    public myCollectionItem(Brush br, myCollectionItemChild child)
    {
        this.myVisualBrush = br;
        this.myItemChild = child;
    }
    public Brush myVisualBrush { get; set; }
    public myCollectionItemChild myItemChild { get; set; }
}

public class myCollectionItemChild
{
    public myCollectionItemChild(string label, double val, double min, double max)
    {
        this.myValueLabel = label;
        this.myValue = val;
        this.myValueMin = min;
        this.myValueMax = max;
    }
    public string myValueLabel { get; set; }
    public double myValue { get; set; }
    public double myValueMax { get; set; }
    public double myValueMin { get; set; }
}

Also, you don't need to use control templates. It can be written more clearly:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="80"></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
    </Grid.RowDefinitions>

    <!-- Combo Box for selection of item-->
    <ComboBox Grid.Row="0" ItemsSource="{Binding myCollectionView, Mode=TwoWay}" IsSynchronizedWithCurrentItem="True">
        <ComboBox.ItemTemplate>
            <DataTemplate DataType="{x:Type vm:myCollectionItem}" >
                <StackPanel>
                    <Rectangle Height="40" Width="40" Fill="{Binding myVisualBrush}"/>
                </StackPanel>
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>

    <!-- Panel to preview item-->
    <Rectangle Margin="20" Fill="{Binding myCollectionView/myVisualBrush}" Grid.Row="1" />

    <!-- Slider to edit item-->
    <StackPanel Grid.Row="2" DataContext="{Binding myCollectionView/myItemChild}">
        <Label Content="{Binding myValueLabel, Mode=OneWay}"/>
        <Slider Value="{Binding myValue, Mode=TwoWay}" Maximum="{Binding myValueMax}" Minimum="{Binding myValueMin}"/>
    </StackPanel>
</Grid>