ObservableCollection.CollectionChanged does not select the correct DataTemplate on ToolBar
Asked Answered
S

2

6

I have a ToolBar with 3 DataTemplates for my Items:

  <ToolBar ItemsSource="{Binding ContextActions}" Background="Transparent" ToolBarTray.IsLocked="True">
        <ToolBar.Resources>
            <DataTemplate DataType="{x:Type viewModels:SimpleContextActionViewModel}">
                <Button Command="{Binding ActionCommand}" Style="{StaticResource ToolBarButtonStyle}" ToolTip="{userInterface:Translation Binding={Binding ToolTip}}">
                    <ContentControl Template="{Binding Icon,Converter={StaticResource NameToResourceConverter}}" Margin="5" />
                </Button>
            </DataTemplate>
            <DataTemplate DataType="{x:Type viewModels:SeparatorViewModel}">
                <Rectangle Fill="{StaticResource SeparatorBrush}" Width="1" VerticalAlignment="Stretch" Margin="2,7" />
            </DataTemplate>
            <DataTemplate DataType="{x:Type viewModels:PopupContextActionViewModel}">
                <Grid>
                    <ToggleButton IsChecked="{Binding ElementName=ContextActionPopup, Mode=TwoWay,Path=IsOpen}" Style="{StaticResource ToolBarButtonStyle}"
                                  ToolTip="{userInterface:Translation Binding={Binding ToolTip}}">
                        <ContentControl Template="{Binding Icon, Converter={StaticResource NameToResourceConverter}}" Margin="5" />
                    </ToggleButton>
                    <Popup Name="ContextActionPopup" Height="150" Width="150" StaysOpen="False">
                        <Border BorderBrush="{StaticResource PopupBorderBrush}" BorderThickness="1" Background="White">
                            <ContentControl userInterface:RegionHelper.RegionName="{Binding RegionId}" />
                        </Border>
                    </Popup>
                </Grid>
            </DataTemplate>
        </ToolBar.Resources>
    </ToolBar>

The ItemsSource is a ObservableCollection<object>

The first three items are already available in the constructor of my ViewModel, those three use the DataTemplates as expected.

If I add another "SimpleContextActionViewModel" to the ObservableCollection, the ToolBar only adds a ContentPresenter which calls ToString. If I add the following line to reasign the ObservableCollection to a new one, everything works fine:

this.ContextActions = new ObservableCollection<object>(this.ContextActions);

this triggers the NotifyPropertyChanged Implementation of my ViewModel and all Items are recreated and look fine.

Why does a CollectionChanged of my ObservableCollection not select a valid DataTemplate while PropertyChanged does?.

This is how it looks This is how it looks

Sprout answered 8/6, 2015 at 14:30 Comment(0)
E
3

I have seen this happen before with the toolbar when used with the collection getting changed anywhere other than the constructor.

Instead of adding your data templates in toolbar resources, add them to the app.xaml then you will see that your code will work as it should. Try this and let me know if it is still not working

Electra answered 8/6, 2015 at 19:16 Comment(2)
I will try that out tomorrow, although it feels really dirty to manage so specific data templates at the application level.Sprout
@Console not sure exactly why the standard approach doesnt work. I stumbled across this sometime ago. If you want a different solution, Can you try implementing an ItemTemplateSelector and see if you can assign DataTemplates that way?Electra
D
1

I'm not certain whether this applies in your case, but your problem seems remarkably similar to: Wiring up CollectionChanged and PropertyChanged (Or : Why do some WPF Bindings not refresh?)

From the accepted answer on that link:

If you don't provide WPF with a template for a data item (such as the Person objects in your list), it'll default to using the ToString() method to display. That's a member, not a property, and so you get no event notification when the value changes.

If you add DisplayMemberPath="Name" to your listbox, it'll generate a template that binds properly to the Name of your person - which will then update automatically as you'd expect.

Could you apply a DisplayMemberPath to the toolbox so that it does not use ToString() by default to render, but rather triggers the NotifyPropertyChanged?

Descry answered 8/6, 2015 at 17:49 Comment(1)
I don't think this relates to my example, I have defined a DataTemplate to display my data, and it works as expected for some items. There is no need to use DisplayMemberPath if you define a DataTemplate on how to display a class. And it is not possible to achive what I want with a display member path.Sprout

© 2022 - 2024 — McMap. All rights reserved.