1
votes

I am trying to set Combobox Selected Item property to null through Control Template I've added Checkbox so I can use datatrigger and set SelectedItem to null when Checkbox isChecked is true. Basically Im trying to add clear filter checkbox that will show up when SelectedItem has some value, and upon clicking this checkbox selected item will null itself

PS.Initially I was going to use button instead of checkbox but Im not sure how to wire it up all inside Dictionary

<CheckBox Panel.ZIndex="2" Width="20" HorizontalAlignment="Left" Foreground="Red" FontWeight="Bold" Background="Red" Content="X" x:Name="chkBOX">
    <CheckBox.Style>
        <Style TargetType="CheckBox">
            <Style.Setters>
                <Setter Property="Visibility" Value="Visible"/>
                <Setter Property="IsEnabled" Value="True"/>
                <Setter Property="VerticalAlignment" Value="Center"/>
            </Style.Setters>
            <Style.Triggers>
                <!-- If selected item is null hide toggle button -->
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}, Path=SelectedItem}" Value="{x:Null}">
                    <Setter Property="Visibility" Value="Hidden"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </CheckBox.Style>
</CheckBox>

And now Im looking to interact with it so selected item goes null when checkbox is checked Hope thats ok :)

EDIT: I've made SOME progress I can null selected item with below however this only works if Selected item is not binded on my window form IE this works

        <ComboBox Grid.Row="1" Margin="10,0,0,0" ItemsSource="{Binding Users}" Tag="Select Full Name" 
                  DisplayMemberPath="FullName" Template="{DynamicResource ComboBoxWithPlaceholder}"  />

this doesnt work

        <ComboBox Grid.Row="1" Margin="10,0,0,0" ItemsSource="{Binding Users}" Tag="Select Full Name" 
                  DisplayMemberPath="FullName" SelectedItem="{Binding SelectedUserFullName}" Template="{DynamicResource ComboBoxWithPlaceholder}"  />
1
Could you please show us the code where the exact problem is? There is too much of code in the question to find where you have a problem. - Shivani Katukota
Sure! I've removed templated defaults and left only checkbox which lives inside grid, inside default control template for combobox. I just want to set selected item property of this combobox to null when checkbox is checked - User
Why don't you bind your CheckBox to the view-model's SelectedUserFullName property, like you do it for the ComboBox? The you can set it to null. - dymanoid
I wanted to separate this control template from being dependant on viewmodels, I wanted to create universal combobox which I can clear and set back to null, I've got around it will post my solutions in answers - User

1 Answers

0
votes

Nullable combobox with placeholeder

Link to gif

<ControlTemplate x:Key="ComboBoxWithPlaceholder" x:Name="cb" TargetType="{x:Type ComboBox}">

    <Grid x:Name="templateRoot" SnapsToDevicePixels="True">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="16"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Width="0"/>
        </Grid.ColumnDefinitions>
        <ToggleButton Panel.ZIndex="2" Width="16" HorizontalAlignment="Left" Foreground="Red" ToolTip="Clear Selection" Opacity="0.5"
                      FontWeight="Bold" Background="Transparent" BorderThickness="0"  Content="X" x:Name="toggleB">
            <ToggleButton.Style>
                <Style TargetType="ToggleButton">
                    <Style.Setters>
                        <Setter Property="VerticalAlignment" Value="Center"/>
                    </Style.Setters>
                    <Style.Triggers>
                        <!-- If selected item is null hide toggle button -->
                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}, Path=SelectedItem}" Value="{x:Null}">
                            <Setter Property="Visibility" Value="Collapsed"/>
                            <!-- When hidden ensure its not checked -->
                            <Setter Property="IsChecked" Value="False"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ToggleButton.Style>
        </ToggleButton>
        <!-- Placeholder textblock text is bound to tag property of combobox -->
        <TextBlock Grid.ColumnSpan="2" Grid.Column="0" x:Name="tb" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Foreground="DimGray"
                   IsHitTestVisible="False" Panel.ZIndex="1" Text="{Binding Tag,RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}}">
            <TextBlock.Style>
                <Style TargetType="TextBlock">
                    <Style.Setters>
                        <Setter Property="Visibility" Value="Hidden"/>
                        <Setter Property="Margin" Value="5,0"/>
                        <Setter Property="VerticalAlignment" Value="{Binding VerticalContentAlignment,RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}}"/>
                    </Style.Setters>
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}, Path=SelectedItem}" Value="{x:Null}">
                            <Setter Property="Visibility" Value="Visible"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </TextBlock.Style>
        </TextBlock>
        <Popup x:Name="PART_Popup" AllowsTransparency="True" Grid.ColumnSpan="2" IsOpen="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
            <Themes:SystemDropShadowChrome x:Name="shadow" Color="Transparent" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding ActualWidth, ElementName=templateRoot}">
                <Border x:Name="DropDownBorder" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
                    <ScrollViewer x:Name="DropDownScrollViewer">
                        <Grid x:Name="grid" RenderOptions.ClearTypeHint="Enabled">
                            <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>
                            <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                        </Grid>
                    </ScrollViewer>
                </Border>
            </Themes:SystemDropShadowChrome>
        </Popup>
        <ToggleButton x:Name="toggleButton" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" VerticalContentAlignment="Center"
                      Background="{TemplateBinding Background}" Grid.Column="0" Grid.ColumnSpan="3" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}">
            <ToggleButton.Style>
                <Style TargetType="{x:Type ToggleButton}">
                    <Setter Property="OverridesDefaultStyle" Value="True"/>
                    <Setter Property="IsTabStop" Value="False"/>
                    <Setter Property="Focusable" Value="False"/>
                    <Setter Property="ClickMode" Value="Press"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type ToggleButton}">
                                <Border x:Name="templateRoot" BorderBrush="#FFACACAC" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="True">
                                    <Border.Background>
                                        <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                                            <GradientStop Color="#FFF0F0F0" Offset="0"/>
                                            <GradientStop Color="#FFE5E5E5" Offset="1"/>
                                        </LinearGradientBrush>
                                    </Border.Background>
                                    <Border x:Name="splitBorder" BorderBrush="Transparent" BorderThickness="1" HorizontalAlignment="Right" Margin="0" SnapsToDevicePixels="True" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}">
                                        <Path x:Name="Arrow" Data="F1M0,0L2.667,2.66665 5.3334,0 5.3334,-1.78168 2.6667,0.88501 0,-1.78168 0,0z" Fill="#FF606060" HorizontalAlignment="Center" Margin="0" VerticalAlignment="Center"/>
                                    </Border>
                                </Border>
                                <ControlTemplate.Triggers>
                                    <MultiDataTrigger>
                                        <MultiDataTrigger.Conditions>
                                            <Condition Binding="{Binding IsEditable, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ComboBox}}}" Value="true"/>
                                            <Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="false"/>
                                            <Condition Binding="{Binding IsPressed, RelativeSource={RelativeSource Self}}" Value="false"/>
                                            <Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="true"/>
                                        </MultiDataTrigger.Conditions>
                                        <Setter Property="Background" TargetName="templateRoot" Value="White"/>
                                        <Setter Property="BorderBrush" TargetName="templateRoot" Value="#FFABADB3"/>
                                        <Setter Property="Background" TargetName="splitBorder" Value="Transparent"/>
                                        <Setter Property="BorderBrush" TargetName="splitBorder" Value="Transparent"/>
                                    </MultiDataTrigger>
                                    <Trigger Property="IsMouseOver" Value="True">
                                        <Setter Property="Fill" TargetName="Arrow" Value="Black"/>
                                    </Trigger>
                                    <MultiDataTrigger>
                                        <MultiDataTrigger.Conditions>
                                            <Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="true"/>
                                            <Condition Binding="{Binding IsEditable, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ComboBox}}}" Value="false"/>
                                        </MultiDataTrigger.Conditions>
                                        <Setter Property="Background" TargetName="templateRoot">
                                            <Setter.Value>
                                                <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                                                    <GradientStop Color="#FFECF4FC" Offset="0"/>
                                                    <GradientStop Color="#FFDCECFC" Offset="1"/>
                                                </LinearGradientBrush>
                                            </Setter.Value>
                                        </Setter>
                                        <Setter Property="BorderBrush" TargetName="templateRoot" Value="#FF7EB4EA"/>
                                    </MultiDataTrigger>
                                    <MultiDataTrigger>
                                        <MultiDataTrigger.Conditions>
                                            <Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="true"/>
                                            <Condition Binding="{Binding IsEditable, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ComboBox}}}" Value="true"/>
                                        </MultiDataTrigger.Conditions>
                                        <Setter Property="Background" TargetName="templateRoot" Value="White"/>
                                        <Setter Property="BorderBrush" TargetName="templateRoot" Value="#FF7EB4EA"/>
                                        <Setter Property="Background" TargetName="splitBorder">
                                            <Setter.Value>
                                                <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                                                    <GradientStop Color="#FFEBF4FC" Offset="0"/>
                                                    <GradientStop Color="#FFDCECFC" Offset="1"/>
                                                </LinearGradientBrush>
                                            </Setter.Value>
                                        </Setter>
                                        <Setter Property="BorderBrush" TargetName="splitBorder" Value="#FF7EB4EA"/>
                                    </MultiDataTrigger>
                                    <Trigger Property="IsPressed" Value="True">
                                        <Setter Property="Fill" TargetName="Arrow" Value="Black"/>
                                    </Trigger>
                                    <MultiDataTrigger>
                                        <MultiDataTrigger.Conditions>
                                            <Condition Binding="{Binding IsPressed, RelativeSource={RelativeSource Self}}" Value="true"/>
                                            <Condition Binding="{Binding IsEditable, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ComboBox}}}" Value="false"/>
                                        </MultiDataTrigger.Conditions>
                                        <Setter Property="Background" TargetName="templateRoot">
                                            <Setter.Value>
                                                <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                                                    <GradientStop Color="#FFDAECFC" Offset="0"/>
                                                    <GradientStop Color="#FFC4E0FC" Offset="1"/>
                                                </LinearGradientBrush>
                                            </Setter.Value>
                                        </Setter>
                                        <Setter Property="BorderBrush" TargetName="templateRoot" Value="#FF569DE5"/>
                                    </MultiDataTrigger>
                                    <MultiDataTrigger>
                                        <MultiDataTrigger.Conditions>
                                            <Condition Binding="{Binding IsPressed, RelativeSource={RelativeSource Self}}" Value="true"/>
                                            <Condition Binding="{Binding IsEditable, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ComboBox}}}" Value="true"/>
                                        </MultiDataTrigger.Conditions>
                                        <Setter Property="Background" TargetName="templateRoot" Value="White"/>
                                        <Setter Property="BorderBrush" TargetName="templateRoot" Value="#FF569DE5"/>
                                        <Setter Property="Background" TargetName="splitBorder">
                                            <Setter.Value>
                                                <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                                                    <GradientStop Color="#FFDAEBFC" Offset="0"/>
                                                    <GradientStop Color="#FFC4E0FC" Offset="1"/>
                                                </LinearGradientBrush>
                                            </Setter.Value>
                                        </Setter>
                                        <Setter Property="BorderBrush" TargetName="splitBorder" Value="#FF569DE5"/>
                                    </MultiDataTrigger>
                                    <Trigger Property="IsEnabled" Value="False">
                                        <Setter Property="Fill" TargetName="Arrow" Value="#FFBFBFBF"/>
                                    </Trigger>
                                    <MultiDataTrigger>
                                        <MultiDataTrigger.Conditions>
                                            <Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="false"/>
                                            <Condition Binding="{Binding IsEditable, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ComboBox}}}" Value="false"/>
                                        </MultiDataTrigger.Conditions>
                                        <Setter Property="Background" TargetName="templateRoot" Value="#FFF0F0F0"/>
                                        <Setter Property="BorderBrush" TargetName="templateRoot" Value="#FFD9D9D9"/>
                                    </MultiDataTrigger>
                                    <MultiDataTrigger>
                                        <MultiDataTrigger.Conditions>
                                            <Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="false"/>
                                            <Condition Binding="{Binding IsEditable, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ComboBox}}}" Value="true"/>
                                        </MultiDataTrigger.Conditions>
                                        <Setter Property="Background" TargetName="templateRoot" Value="White"/>
                                        <Setter Property="BorderBrush" TargetName="templateRoot" Value="#FFBFBFBF"/>
                                        <Setter Property="Background" TargetName="splitBorder" Value="Transparent"/>
                                        <Setter Property="BorderBrush" TargetName="splitBorder" Value="Transparent"/>
                                    </MultiDataTrigger>
                                </ControlTemplate.Triggers>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </ToggleButton.Style>
        </ToggleButton>
        <ContentPresenter Grid.Column="1" x:Name="contentPresenter" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"  ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" 
                          Content="{TemplateBinding SelectionBoxItem}" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                          IsHitTestVisible="False" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
        </ContentPresenter>
    </Grid>

    <ControlTemplate.Triggers>
        <!-- If selected set selected item to null-->
        <DataTrigger Binding="{Binding IsPressed, ElementName=toggleB}" Value="True">
            <Setter Property="SelectedValue" Value="{x:Null}"/>
            <Setter Property="SelectedValuePath" Value="{x:Null}"/>
            <Setter Property="SelectedItem" Value="{x:Null}"/>
        </DataTrigger>
        <Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="True">
            <Setter Property="Margin" TargetName="shadow" Value="0,0,5,5"/>
            <Setter Property="Color" TargetName="shadow" Value="#71000000"/>
        </Trigger>
        <Trigger Property="HasItems" Value="False">
            <Setter Property="Height" TargetName="DropDownBorder" Value="95"/>
        </Trigger>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsGrouping" Value="True"/>
                <Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="False"/>
            </MultiTrigger.Conditions>
            <Setter Property="ScrollViewer.CanContentScroll" Value="False"/>
        </MultiTrigger>
        <Trigger Property="CanContentScroll" SourceName="DropDownScrollViewer" Value="False">
            <Setter Property="Canvas.Top" TargetName="OpaqueRect" Value="{Binding VerticalOffset, ElementName=DropDownScrollViewer}"/>
            <Setter Property="Canvas.Left" TargetName="OpaqueRect" Value="{Binding HorizontalOffset, ElementName=DropDownScrollViewer}"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

bit I was missing is to set SelectedValuePath and SelectedValue to null as well as Selected item

    <DataTrigger Binding="{Binding IsPressed, ElementName=toggleB}" Value="True">
        <Setter Property="SelectedValue" Value="{x:Null}"/>
        <Setter Property="SelectedValuePath" Value="{x:Null}"/>
        <Setter Property="SelectedItem" Value="{x:Null}"/>
    </DataTrigger>