1

I have a ListBox filled with Apples. I wanted to change the selected item to only have a solid background with no border. I followed this suggestion:

Question #146269: Change Wpf Datatemplate for Listbox Item if Selected

Here is my xaml:

<UserControl.Resources>
    <ResourceDictionary>
        <DataTemplate x:Key="AppleItemTemplate">
            <Border Opacity="1" Padding="10,5">
                    <TextBlock Foreground="{DynamicResource PrimaryTextColor}">
                    <TextBlock.Text>
                        <Binding Path="DisplayName"/>
                    </TextBlock.Text>
                </TextBlock>
            </Border>
        </DataTemplate>
        <DataTemplate x:Key="AppleItemTemplateSelected">
            <Border BorderThickness="0" BorderBrush="Transparent" Padding="10,5" Background="{DynamicResource LeftSidebarBGColorHighlight}">
                <TextBlock Foreground="{DynamicResource PrimaryTextColor}">
                    <TextBlock.Text>
                        <Binding Path="DisplayName"/>
                    </TextBlock.Text>
                </TextBlock>
            </Border>
        </DataTemplate>
        <Style TargetType="{x:Type ListBoxItem}" x:Key="AppleContainerStyle">
            <Setter Property="ContentTemplate" Value="{DynamicResource AppleItemTemplate}"/>
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="ContentTemplate" Value="{DynamicResource AppleItemTemplateSelected}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ResourceDictionary>
</UserControl.Resources>

<ListBox ItemsSource="{Binding Apples}"
         SelectedItem="{Binding SelectedApple}"
         ItemContainerStyle="{StaticResource AppleContainerStyle}"

         Background="{DynamicResource LeftSidebarBGColor}"
         BorderThickness="0"
         ScrollViewer.HorizontalScrollBarVisibility="Disabled" HorizontalContentAlignment="Stretch"
         >

    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>

When I run the program, and select an apple, I get this:

Selected Apple

You can see that the XAML is working to apply a grey background color. But there's a white border that shouldn't be there. If you look closely, there are also subtle grey bands on the left and right sides of the box just inside the border. (sad face)

Does anyone know what's wrong with my Data Template or my ListBox settings?

JamesHoux
  • 2,999
  • 3
  • 32
  • 50

2 Answers2

1

If you just want to remove the border of selected item,try this :

Add <Setter Property="BorderThickness" Value="0"/> in the trigger "IsSelected".

In my demo , I found it works.

FranklinLee
  • 309
  • 2
  • 9
  • I just smacked my own forehead. Thank you, so much! – JamesHoux Jan 16 '19 at 03:05
  • 1
    That works, but it's a bit of a hack because the border element is still there. What's happening is that the ItemListBox uses a template that contains the border and a ContentPresenter, and you're setting the Data Template for the ContentPresenter to use i.e. the wrapper is still there. What you need to do is change your DataTemplates to ControlTemplates and set the ListBoxItem style's "Template" property instead of "ContentTemplate". – Mark Feldman Jan 16 '19 at 03:07
  • @MarkFeldman Thanks Mark, I did what you said and it worked, but some additional changes were required to get clicking to work right. I'll add my result in a final answer – JamesHoux Jan 16 '19 at 18:20
  • @MarkFeldman After researching the difference between DataTemplate and ControlTemplate, it seems to me that the distinction between them is maligned with actual use. I read this discussion: https://stackoverflow.com/questions/1340108/difference-between-control-template-and-datatemplate-in-wpf The whole thing makes it sound like deciding whether to use controltemplate or datatemplate is just a matter of "what" you're displaying. But based on the problem in my example, it looks more like "how" you need to display it really governs everything. Can you shed light on this? – JamesHoux Jan 16 '19 at 19:58
  • 1
    It's a subtle difference, but an important one. Take a custom button, for example. In general you'll want to be able to specify the overall look i.e. border thickness, highlight color etc, and that will be the same for all buttons. The content inside that button, on the other hand, might be all sorts of different things...text, an image, a collection of controls etc, and how you want that content rendered will be dictated by the data that the button's Content property is Binding to. The overall look of the button is controlled by the ContentControl, the content is controlled by DataTemplates. – Mark Feldman Jan 17 '19 at 07:10
  • 1
    I think the confusion sometimes arises because people only need a single DataTemplate because they're only rendering one type of data. In that case yes, you can often achieve exactly the same result by overriding either the ControlTemplate or the DataTemplate. But what DataTemplates do is allow you to create a single control that can render lots of different types of data by specifying multiple DataTemplates, one for each type. And you can do it without having to re-create the entire control from scratch for every one of those types. – Mark Feldman Jan 17 '19 at 07:13
  • 1
    It's a tricky thing to get your head around because we never had this level of control in WinForms or MFC etc. What WPF does is provide a much higher level of customization, but when poorly designed it can create a lot more work for the GUI developers. The ControlTemplate/DataTemplate paradigms save you a huge amount of time and work once your interfaces start becoming more complex and more data-driven. – Mark Feldman Jan 17 '19 at 07:15
  • 1
    @MarkFeldman So, it sounds like it could be appropriate to use both a ControlTemplate and a DataTemplate, correct? An example would be if you wanted to create a common button style using a control template but then have different instances of that button displaying different types of data with different data templates. Is this right? – JamesHoux Jan 17 '19 at 17:14
  • 1
    Exactly. If you only have one type of data then you may as well just use a ControlTemplate. Once you have different types of data you use a ControlTemplate to dictate the overall look and then DataTemplates to style the look of the different data types you're displaying.The `ContentPresenter` is what you put inside the ControlTemplate to say "the actual content goes here". – Mark Feldman Jan 17 '19 at 20:11
1

MarkFeldman's answer worked, but there was a mouse click event problem. With the Padding on the Border element, mouse clicks would not register when clicking in the padded area between text items. To fix it, I replaced the Border with a StackPanel, and moved the Padding onto the TextBlock. Padding on the textblock itself registers a click properly.

Final xaml:

<UserControl.Resources>
<ResourceDictionary>
    <ControlTemplate x:Key="AppleItemTemplate">
        <StackPanel Opacity="1">
                <TextBlock Padding="10,5" Foreground="{DynamicResource PrimaryTextColor}">
                <TextBlock.Text>
                    <Binding Path="DisplayName"/>
                </TextBlock.Text>
            </TextBlock>
        </StackPanel>
    </ControlTemplate>
    <ControlTemplate x:Key="AppleItemTemplateSelected">
        <StackPanel Background="{DynamicResource LeftSidebarBGColorHighlight}">
            <TextBlock Padding="10,5" Foreground="{DynamicResource PrimaryTextColor}">
                <TextBlock.Text>
                    <Binding Path="DisplayName"/>
                </TextBlock.Text>
            </TextBlock>
        </StackPanel>
    </ControlTemplate>
    <Style TargetType="{x:Type ListBoxItem}" x:Key="AppleContainerStyle">
        <Setter Property="Template" Value="{DynamicResource AppleItemTemplate}"/>
        <Style.Triggers>
            <Trigger Property="IsSelected" Value="True">
                <Setter Property="Template" Value="{DynamicResource AppleItemTemplateSelected}"/>
                <Setter Property="BorderThickness" Value="0"/>
            </Trigger>
        </Style.Triggers>
    </Style>
</ResourceDictionary>

JamesHoux
  • 2,999
  • 3
  • 32
  • 50