15

We have a scenario where we want to display a list of items and indicate which is the "current" item (with a little arrow marker or a changed background colour).

ItemsControl is no good to us, because we need the context of "SelectedItem". However, we want to move the selection programattically and not allow the user to change it.

Is there a simple way to make a ListBox non-interactive? We can fudge it by deliberately swallowing mouse and keyboard events, but am I missing some fundamental property (like setting "IsEnabled" to false without affecting its visual style) that gives us what we want?

Or ... is there another WPF control that's the best of both worlds - an ItemsControl with a SelectedItem property?

Matt Hamilton
  • 200,371
  • 61
  • 386
  • 320

4 Answers4

19

One option is to set ListBoxItem.IsEnabled to false:

<ListBox x:Name="_listBox">
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="IsEnabled" Value="False"/>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

This ensures that the items are not selectable, but they may not render how you like. To fix this, you can play around with triggers and/or templates. For example:

<ListBox x:Name="_listBox">
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="IsEnabled" Value="False"/>
            <Style.Triggers>
                <Trigger Property="IsEnabled" Value="False">
                    <Setter Property="Foreground" Value="Red" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>
Kent Boogaart
  • 175,602
  • 35
  • 392
  • 393
  • Your ControlTemplate is doing a DataTemplate's job. All you need in addition to the Setter for IsEnabled is – Joel B Fant Oct 02 '08 at 20:05
  • You could also set the items as invisible to hit testing (Setter Property="IsHitTestVisible" Value="False"), so they will render as usual (not grayed because of being disabled) and the scrollbar will still work. – Néstor Sánchez A. Oct 17 '21 at 20:47
3

I had the same issue. I resolved it by leaving the IsEnabled set to true and handling the PreviewMouseDown event of the ListBox. In the handler set e.Handled to true in the case you don't want it to be edited.

    private void lstSMTs_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        e.Handled = !editRights;
    }
Jim
  • 31
  • 1
  • You can still change the selections by using the keyboard. Also scroll bars won't work – Neil Oct 17 '13 at 14:59
3

The magical incantation that will do the trick is:

<ListBox IsHitTestVisible="False">

Unfortunately, this will also prevent any scrollbars from working.

The fix to that is to put the listbox inside a scrollviewer:

<ScrollViewer>
    <ListBox IsHitTestVisible="False">
    </ListBox>
</ScrollViewer>
Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
1

Is your ItemsControl/ListBox databound?

I'm just thinking you could make the Background Brush of each item bound to a property from the source data, or pass the property through a converter. Something like:

  <ItemsControl DataContext="{Binding Source={StaticResource Things}}" ItemsSource="{Binding}" Margin="0">
    <ItemsControl.Resources>
      <local:SelectedConverter x:Key="conv"/>
    </ItemsControl.Resources>
    <ItemsControl.ItemsPanel>
      <ItemsPanelTemplate>
        <local:Control Background="{Binding Path=IsSelected, Converter={StaticResource conv}}"/>
      </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
Mark Glorie
  • 3,733
  • 3
  • 28
  • 31