I am using sdl/Multiselect-ComboBox inside my UserControl which is collapsed by default. On press of a button the UserControl Visibility is set to visible and hence every thing should be loaded in Visual Tree. If visibility is set to Visible the repository controls are called in this order.
1) static MultiSelectComboBox()
2) public override void OnApplyTemplate()
3) Dependency Properties Call Backs.
When Events are in this order. Every thing work as expected.
But when visibility is set to Collapsed By default. Dependency Property is called before OnApplyTemplate which is understandable. The problem is following call back Load all properties and bind all events required.
private static void ItemsPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
LoadComponents(dependencyObject, dependencyPropertyChangedEventArgs);
}
private static void LoadComponents(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var control = dependencyObject as MultiSelectComboBox;
if (control?.MultiSelectComboBoxGrid != null && control?.ItemsSource != null)
{
control.ItemsCollectionViewSource = new CollectionViewSource
{
Source = control.ItemsSource
};
if (dependencyPropertyChangedEventArgs.NewValue is IList newItems && newItems.Count > 0)
{
control.UpdateSelectedItemsContainer(newItems);
}
if (control.SelectedItemsControl == null)
{
control.SelectedItemsControl = VisualTreeService.FindVisualChild<ItemsControl>(control.MultiSelectComboBoxGrid, PART_MultiSelectComboBox_SelectedItemsPanel_ItemsControl);
}
if (control.DropdownListBox == null)
{
if (control.DropdownMenu == null)
{
control.DropdownMenu = VisualTreeService.FindVisualChild<Popup>(control.MultiSelectComboBoxGrid, PART_MultiSelectComboBox_Dropdown);
}
if (control.DropdownMenu != null)
{
control.DetachedFilterPanel = VisualTreeService.FindVisualChild<StackPanel>(control.DropdownMenu.Child, PART_MultiSelectComboBox_Detached_FilterPanel);
if (control.DetachedFilterPanel != null)
{
control.DetachedFilterTextBox = VisualTreeService.FindVisualChild<TextBox>(control.DetachedFilterPanel, PART_MultiSelectComboBox_Detached_Filter_TextBox);
control.DetachedFilterAutoCompleteTextBox = VisualTreeService.FindVisualChild<TextBox>(control.DetachedFilterPanel, PART_MultiSelectComboBox_Detached_Filter_AutoComplete_TextBox);
}
control.DropdownListBox = VisualTreeService.FindVisualChild<ListBox>(control.DropdownMenu.Child, PART_MultiSelectComboBox_Dropdown_ListBox);
}
}
}
}
This in my scenario is called before OnApplyTemplate so I made a function Called LoadComponent Function and called it from OnApplyTemplate as well. Every thing works fine except the following is always giving null and when I inspected Visual tree its not even there
if (control.SelectedItemsControl == null)
{
control.SelectedItemsControl = VisualTreeService.FindVisualChild<ItemsControl>(control.MultiSelectComboBoxGrid, PART_MultiSelectComboBox_SelectedItemsPanel_ItemsControl);
}
I am unable to understand reason behind this. Here is Xaml for this part
<DataTemplate x:Key="MultiSelectComboBox.SelectedItemsPanel.Template">
<Border Background="White" BorderBrush="{StaticResource MultiSelectComboBox.SelectedItemsPanel.Border}" BorderThickness="1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Margin="1" Background="White" BorderThickness="0">
<sdl:ContentItemsControl x:Name="PART_MultiSelectComboBox_SelectedItemsPanel_ItemsControl"
ItemContainerStyle="{StaticResource MultiSelectComboBox.SelectedItems.ItemContainer.Style}"
Style="{StaticResource MultiSelectComboBox.SelectedItemsPanel.WrapableItemsSource.Style}">
<sdl:ContentItemsControl.Resources>
<DataTemplate x:Key="MultiSelectComboBox.SelectedItems.ItemTemplate">
<TextBlock Text="{Binding}" Style="{DynamicResource MultiSelectComboBox.DefaultTextBlock.Style}" Margin="2,0" />
</DataTemplate>
<DataTemplate x:Key="MultiSelectComboBox.SelectedItems.Searchable.ItemTemplate">
<StackPanel Orientation="Horizontal">
<TextBox x:Name="PART_MultiSelectComboBox_SelectedItemsPanel_Filter_TextBox" IsEnabled="{Binding IsEditMode, RelativeSource={RelativeSource TemplatedParent}}"
Focusable="True" IsTabStop="False" Margin="0" ForceCursor="True" BorderThickness="0" BorderBrush="Transparent" Padding="1" TextWrapping="NoWrap"/>
<TextBox x:Name="PART_MultiSelectComboBox_SelectedItemsPanel_Filter_AutoComplete_TextBox" IsReadOnly="True"
Focusable="False" IsTabStop="False" Margin="-2,0,0,0" BorderThickness="0" BorderBrush="Transparent" Padding="-3,1,0,1" TextWrapping="NoWrap"/>
</StackPanel>
</DataTemplate>
</sdl:ContentItemsControl.Resources>
</sdl:ContentItemsControl>
</Border>
<Button x:Name="PART_MultiSelectComboBox_Dropdown_Button" Grid.Column="1" Style="{StaticResource MultiSelectComboBox.DropDown.Button.Style}" >
<ContentControl>
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="ContentTemplate" Value="{StaticResource MultiSelectComboBox.SelectedItemsPanel.Readonly.Glyph.Template}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type sdl:MultiSelectComboBox}}, Path=IsEditMode}" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource MultiSelectComboBox.SelectedItemsPanel.EditMode.Glyph.Template}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</Button>
</Grid>
</Border>
</DataTemplate>
<Style x:Key="MultiSelectComboBox.Custom.Style" TargetType="{x:Type sdl:MultiSelectComboBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type sdl:MultiSelectComboBox}">
<Grid x:Name="PART_MultiSelectComboBox" MaxHeight="{TemplateBinding ActualHeight}" MaxWidth="{TemplateBinding ActualWidth}" Style="{StaticResource MultiSelectComboBox.Style}">
<ToggleButton KeyboardNavigation.TabNavigation="None" IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" IsTabStop="False">
<ToggleButton.Template>
<ControlTemplate TargetType="ToggleButton">
<ContentControl ContentTemplate="{StaticResource MultiSelectComboBox.SelectedItemsPanel.Template}"/>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
<Popup x:Name="PART_MultiSelectComboBox_Dropdown" Margin="2" Grid.ColumnSpan="2" MaxHeight="{Binding Path=MaxDropDownHeight, RelativeSource={RelativeSource TemplatedParent} }" PlacementTarget="{Binding ElementName=PART_MultiSelectComboBox}" IsOpen="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" MaxWidth="{TemplateBinding ActualWidth}" Placement="Bottom" AllowsTransparency="True" PopupAnimation="Slide">
<themes:SystemDropShadowChrome x:Name="shadow" Color="Transparent" MinWidth="{Binding ActualWidth, ElementName=PART_MultiSelectComboBox}">
<Border x:Name="dropDownBorder" Margin="0,1,0,0" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="0" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Visibility="{Binding DetachAutoCompleteFilterBox, RelativeSource={RelativeSource TemplatedParent},Converter={StaticResource BoolToVis},FallbackValue=Collpased}">
<Border BorderBrush="LightBlue" BorderThickness="1">
<Border.Effect>
<DropShadowEffect ShadowDepth="0" Color="LightBlue" Opacity="1" BlurRadius="10"/>
</Border.Effect>
</Border>
<Border Padding="2">
<StackPanel x:Name="PART_MultiSelectComboBox_Detached_FilterPanel" Orientation="Horizontal" Height="30">
<TextBox x:Name="PART_MultiSelectComboBox_Detached_Filter_TextBox" Margin="1,0,0,0" IsEnabled="{Binding IsEditMode, RelativeSource={RelativeSource TemplatedParent}}"
Focusable="True" IsTabStop="False" ForceCursor="True" BorderThickness="0" BorderBrush="Transparent" Padding="1" TextWrapping="NoWrap"/>
<TextBox x:Name="PART_MultiSelectComboBox_Detached_Filter_AutoComplete_TextBox" IsReadOnly="True"
Focusable="False" IsTabStop="False" Margin="-2,0,0,0" BorderThickness="0" BorderBrush="Transparent" Padding="-3,1,0,1" TextWrapping="NoWrap"/>
</StackPanel>
</Border>
</Grid>
<Grid x:Name="grid" Grid.Row="1" RenderOptions.ClearTypeHint="Enabled"
Visibility="{Binding Path=IsLoadingSuggestions,
RelativeSource={RelativeSource Mode=TemplatedParent},
Converter={StaticResource ResourceKey=InvBoolToVis}}"
>
<Grid Visibility="{Binding Path=IsLoadingSuggestions,
RelativeSource={RelativeSource Mode=TemplatedParent},
Converter={StaticResource ResourceKey=InvBoolToVis}}">
<Canvas x:Name="canvas" HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
<Rectangle x:Name="opaqueRect" Fill="{Binding Background, ElementName=dropDownBorder}" Height="{Binding ActualHeight, ElementName=dropDownBorder}" Width="{Binding ActualWidth, ElementName=dropDownBorder}"/>
</Canvas>
<sdl:ExtendedListBox x:Name="PART_MultiSelectComboBox_Dropdown_ListBox" Style="{StaticResource MultiSelectComboBox.Dropdown.ListBox.Style}">
<sdl:ExtendedListBox.GroupStyle>
<GroupStyle HeaderTemplate="{StaticResource MultiSelectComboBox.Dropdown.ListBox.Header.Template}"/>
</sdl:ExtendedListBox.GroupStyle>
<sdl:ExtendedListBox.Resources>
<DataTemplate x:Key="MultiSelectComboBox.Dropdown.ListBox.ItemTemplate">
<TextBlock Text="{Binding}" Style="{StaticResource MultiSelectComboBox.DefaultTextBlock.Style}" Margin="2,2,2,3"/>
</DataTemplate>
</sdl:ExtendedListBox.Resources>
</sdl:ExtendedListBox>
</Grid>
<ContentPresenter ContentSource="LoadingSuggestionsContent"
Visibility="{Binding Path=IsLoadingSuggestions,
RelativeSource={RelativeSource Mode=TemplatedParent},
Converter={StaticResource ResourceKey=BoolToVis}}"/>
</Grid>
</Grid>
</Border>
</themes:SystemDropShadowChrome>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I have wasted my day trying to think of a possible reason but unable to get this working.