ListBox.SelectionMode = «None» отсутствует, есть ли другой способ отключить выбор в списке?

189

Как отключить выбор в ListBox?

Шимми Вайцхандлер
источник
1
Не могли бы вы привести пример, когда допустимо иметь ListBox, который вы не можете выбрать? Поскольку основное поведение заключается в выборе предметов. Я бы, вероятно, выбрал другой способ показать это. (Это не я пытаюсь быть критиком, а скорее искренний интерес к тому, где это может произойти)
Мартин
3
@Martin: например, если вы хотите перетащить содержимое из элемента списка - в этом случае вы, вероятно, не заинтересованы в выборе этого элемента. ТАКЖЕ: при перетаскивании элемента: выбранный элемент списка изменяется при перетаскивании внутри списка - см. Эту запись stackoverflow.com/questions/7589142/…
Danield
1
Я считаю, что причина, по которой Шимми хочет использовать ListBox, заключается в том, что спрашивающий может когда-нибудь сделать список доступным для выбора. Вопрос также ценен для меня. Скажем, вы строите карточную игру. Вы можете выбрать одну карту из своих карт, иногда вы можете выбрать несколько, а в другое время вы не можете выбрать любую.
Gqqnbig
1
Кроме того, иногда у вас есть 10 карт, и только 4 из них можно выбрать. Среди 4 вы можете выбрать до 3.
Gqqnbig 18.12.12
1
@Martin: когда у вас есть GridView в ListBox. Заголовки Gridview предоставляют множество функциональных возможностей, недоступных в других местах. И у вас есть элементы управления редактирования в ячейках вида сетки.
Робин Дэвис

Ответы:

264

Подход 1 - ItemsControl

Если вам не нужны другие аспекты ListBox, вы можете использовать ItemsControlвместо этого. Он помещает предметы в ItemsPanelи не имеет понятия выбора.

<ItemsControl ItemsSource="{Binding MyItems}" />

По умолчанию ItemsControlне поддерживает виртуализацию дочерних элементов. Если у вас много элементов, виртуализация может уменьшить использование памяти и повысить производительность, и в этом случае вы можете использовать подход 2 и стилизовать ListBoxили добавить виртуализацию к вашемуItemsControl .

Подход 2 - Стиль ListBox

Либо просто стилизуйте ListBox так, чтобы выделение не было видно.

<ListBox.Resources>
  <Style TargetType="ListBoxItem">
    <Style.Resources>
      <!-- SelectedItem with focus -->
      <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
                       Color="Transparent" />
      <!-- SelectedItem without focus -->
      <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}"
                       Color="Transparent" />
      <!-- SelectedItem text foreground -->
      <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}"
                       Color="Black" />
    </Style.Resources>
    <Setter Property="FocusVisualStyle" Value="{x:Null}" />
  </Style>
</ListBox.Resources>
Дрю Ноакс
источник
24
нет, это только изменит визуальный эффект, а не фактическое поведение выбора
Томас Левеск
8
Моим первым предложением было использовать ItemsControl. Ты скучал по этому? :)
Дрю Ноакс
5
Еще раз перечитывая эти комментарии, я хочу отметить, что комментарий @Thomas Levesque относится только ко второму подходу, который я показываю. Использование равнины ItemsControlполностью удалит любую концепцию выбора.
Дрю Ноакс
1
Решение ItemsControl убирает поддержку прокрутки в окне (полоса прокрутки и колесико мыши).
MuiBienCarlota
1
+1 для подхода 1 - ItemsControl. Если у нас есть огромная страница, которую мы должны прокручивать, если пользователь наводит мышью на ListBox, он эффективно отключает MouseWheel, поскольку список захватывает события MouseWheel. Это означает, что пользователь разочарован тем, что колесо мыши, используемое для прокрутки всей страницы, случайным образом перестанет работать, в зависимости от того, находится мышь над списком или нет.
Contango
160

Я нашел очень простое и понятное решение, работающее на меня, надеюсь, оно подойдет и вам

<ListBox ItemsSource="{Items}">
    <ListBox.ItemContainerStyle>
       <Style TargetType="{x:Type ListBoxItem}">
           <Setter Property="Focusable" Value="False"/>
       </Style>
    </ListBox.ItemContainerStyle>
</ListBox>
Асад Дуррани
источник
Я думаю, что он прошел это довольно хорошо здесь: asaddurrani.wordpress.com/tag/wpf-listbox-disable-selection
Сид
3
Это потрясающе. это предотвращает выбранный элемент и другие элементы управления, такие как кнопки по-прежнему работает именно то, что я искал
Франк
1
+1 за этот подход. Если у нас есть огромная страница, которую мы должны прокручивать, если пользователь наводит мышью на ListBox, он эффективно отключает MouseWheel, поскольку список захватывает события MouseWheel. Это означает, что пользователь разочарован тем, что колесо мыши, используемое для прокрутки всей страницы, случайным образом перестанет работать, в зависимости от того, находится мышь над списком или нет.
Contango
Превосходно. Подобный подход также работал для меня, когда мне нужны были кнопки на элементах, чтобы не вызывать выбор элемента, а только если была нажата другая область элемента. Просто установите кнопки Focusable = "False"!
Джони Адамит
2
Добавьте это дополнительное свойство, чтобы убрать выделение при <Setter Property="IsHitTestVisible" Value="False" />
наведении курсора мыши
25

Вы можете переключиться на использование ItemsControlвместо ListBox. У An ItemsControlнет понятия выбора, поэтому отключать нечего.

Wilka
источник
2
Очаровательный. Я никогда не знал, что вы можете напрямую объявить ItemsControl, я думал, что это виртуальный (MustOverride), спасибо !!!
Шимми Вайцхандлер
Но будет ли ItemsControl отображать мои элементы в одну строку?
Чри Ченг
@ Да, да, и, кроме того, вы всегда можете установить вручную ItemTemplate.
Shimmy Weitzhandler
2
Это приводит к потере слишком большой функциональности - например, прокрутки.
Джефф
@Дафф, вы можете обернуть ItemsControl в ScrollViewer, чтобы получить прокрутку.
Вилка
12

Другой вариант, который стоит рассмотреть, это отключение ListBoxItems. Это можно сделать, установив ItemContainerStyle, как показано в следующем фрагменте.

<ListBox ItemsSource="{Binding YourCollection}">
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="IsEnabled" Value="False" />
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

Если вы не хотите, чтобы текст был серым, вы можете указать отключенный цвет, добавив кисть к ресурсам стиля с помощью следующей клавиши: {x: Static SystemColors.GrayTextBrushKey}. Другое решение - переопределить шаблон элемента управления ListBoxItem.

Калеб Вир
источник
Просто и работает, спасибо! И это применимо и к WP 8.1 Runtime.
Малютек,
8

Это также будет работать, если у меня есть необходимость использовать listbox вместо itemscontrol, но я просто отображаю элементы, которые нельзя выбирать, я использую:

<ListBox.ItemContainerStyle>
    <Style TargetType="ListBoxItem">
        <Setter Property="IsHitTestVisible" Value="False" />
    </Style>
</ListBox.ItemContainerStyle>
Андрей Кикель
источник
3

Здесь довольно хорошие ответы, но я искал что-то немного другое: я хочу выделение, но просто не хочу, чтобы оно отображалось (или показывалось в другом вопросе).

Приведенные выше решения не сработали для меня (полностью), поэтому я сделал кое-что еще: я использовал новый стиль для моего списка, который полностью переопределяет шаблоны:

<Style x:Key="PlainListBoxStyle" TargetType="ListBox">
    <Setter Property="ItemContainerStyle">
        <Setter.Value>
            <Style TargetType="ListBoxItem">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ListBoxItem">
                            <ContentPresenter />
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBox}">
                <ItemsPresenter/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Начиная с этого, вы можете легко добавить собственную подсветку выделения или оставить ее так, если вообще не хотите.

Андреас Калер
источник
2

Хотя ответ @Drew Noakes является быстрым решением для большинства случаев, есть некоторая ошибка, возникающая при установке кистей x: Static.

Когда вы устанавливаете кисти x: Static, как предложено, все дочерние элементы управления в элементе списка будут наследовать этот стиль.

Это означает, что, хотя это будет работать для отключения подсветки элемента списка, это может привести к нежелательным эффектам для дочерних элементов управления.

Например, если у вас есть ComboBox в вашем ListBoxItem, он отключил бы выделение мыши внутри ComboBox.

Вместо этого рассмотрите возможность установки VisualStates для событий Selected, Unselected и MouseOver, как описано в решении, упомянутом в этом потоке stackoverflow: Удалить выделение элемента управления из ListBoxItem, но не дочерние элементы управления .

-Frinny

Frinavale
источник
2

Я предлагаю еще одно решение. Просто повторно шаблон, ListBoxItemчтобы быть не чем иным ContentPresenter, как так ...

<Style TargetType="{x:Type ListBoxItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <ContentPresenter />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Мои причины такого подхода следующие:

  1. В моем случае я не хочу отключать взаимодействие пользователя с содержимым моего, ListBoxItemsпоэтому решение, которое нужно установить IsEnabled, не будет работать для меня.

  2. Другое решение, которое пытается изменить стиль ListBoxItemпутем переопределения связанных с цветом свойств, работает только для тех случаев, когда вы уверены, что шаблон использует эти свойства. Это хорошо для стилей по умолчанию, но нарушает пользовательские стили.

  3. Решения, которые используют ItemsControlразрыв, ломают слишком много других вещей, поскольку ItemsControlвыглядят совершенно иначе, чем стандартные, ListBoxи не поддерживают виртуализацию, что означает, что вам ItemsPanelвсе равно придется повторно шаблонировать.

Вышеприведенное не меняет внешний вид по умолчанию ListBox, не отключает элементы в шаблонах данных для ListBox, поддерживает виртуализацию по умолчанию и работает независимо от стилей, которые могут или не могут использоваться в вашем приложении. Это принцип KISS.

Марк А. Донохо
источник
1

Примечание. Это решение не отключает выбор с помощью навигации по клавиатуре или щелчка правой кнопкой мыши (т. Е. Клавиши со стрелками и пробел)

Все предыдущие ответы либо удаляют возможность выбора полностью (без переключения во время выполнения), либо просто удаляют визуальный эффект, но не выделение.

Но что, если вы хотите иметь возможность выбирать и показывать выбор по коду, а не по пользовательскому вводу? Может быть, вы хотите «заморозить» выбор пользователя, не отключая весь список?

Решение состоит в том, чтобы обернуть весь ItemsContentTemplate в кнопку Button, не имеющую визуального хрома. Размер кнопки должен быть равен размеру Предмета, поэтому он полностью покрыт. Теперь используйте свойство IsEnabled кнопки:

Включите кнопку, чтобы "заморозить" состояние выбора элемента. Это работает, потому что активированная кнопка съедает все события мыши, прежде чем они всплывают в ListboxItem-Eventhandler. Ваш ItemsDataTemplate будет по-прежнему получать MouseEvents, потому что он является частью содержимого кнопок.

Отключите кнопку, чтобы включить изменение выбора, нажав.

<Style x:Key="LedCT" TargetType="{x:Type ListBoxItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <Button IsEnabled="{Binding IsSelectable, Converter={StaticResource BoolOppositeConverter}}" Template="{DynamicResource InvisibleButton}">
                        <ContentPresenter />
                </Button>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<ControlTemplate x:Key="InvisibleButton" TargetType="{x:Type Button}">
    <ContentPresenter/>
</ControlTemplate>

dartrax

dartrax
источник
1

Может быть, вам нужна только функциональность ItemsControl? Не разрешать выбор:

<ItemsControl ItemsSource="{Binding Prop1}" ItemTemplate="{StaticResource DataItemsTemplate}" />
Саша
источник
3
@Shimmy: тривиальные ответы часто бывают похожими. Здесь нет дублирования, достойного какого-либо флага. Если у вас есть еще какие-либо вопросы по этому поводу, пожалуйста, задавайте их в Meta Stack Overflow .
0

Вы можете поместить текстовый блок над списком, он не изменит внешний вид вашего приложения, а также не позволит выбрать какой-либо элемент.

Paras
источник
1
Вам все равно нужно отключить навигацию по вкладкам.
Аманду,
0

Простое исправление, которое работает, например, в Windows Phone, заключается в том, что для выбранного элемента выбран ноль:

    <ListBox SelectionChanged="ListBox_SelectionChanged">

И в коде позади:

    private void ListBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
    {
        (sender as ListBox).SelectedItem = null;
    }
Jason94
источник
0

Я нашел идеальный способ.
Установите для ListBox IsHitTestVisible значение false, чтобы пользователь не мог перемещаться, прокручивать вниз или прокручивать вверх.
Capture PreviewGotKeyboardFocus e.Handled = true, чтобы пользователь мог выбрать элемент с помощью клавиш Tab, стрелки вверх, стрелки вниз.

Преимущество этого способа:

  1. Элементы ListBox переднего плана не станут серыми.
  2. Фон ListBox можно установить прозрачным

xmal

<ListBox Name="StudentsListBox" ItemsSource="{Binding Students}" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled" BorderThickness="0" Background="Transparent" IsHitTestVisible="False" PreviewGotKeyboardFocus="StudentsListBox_PreviewGotKeyboardFocus">

    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="Padding" Value="0"/>
            <Setter Property="Margin" Value="0"/>

            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <Border x:Name="Bd">
                            <ContentPresenter/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="Selector.IsSelectionActive" Value="False" />
                                    <Condition Property="IsSelected" Value="True" />
                                </MultiTrigger.Conditions>
                                <Setter TargetName="Bd" Property="Background" Value="Yellow" />
                                <Setter TargetName="Bd" Property="BorderBrush" Value="Transparent" />
                            </MultiTrigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ListBox.ItemContainerStyle>

    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid Margin="0,0,0,0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" Name="GradeBlock" Text="{Binding Grade}" FontSize="12" Margin="0,0,5,0"/>
                <TextBlock Grid.Column="1" Name="NameTextBlock" Text="{Binding Name}" FontSize="12" TextWrapping="Wrap"/>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>

</ListBox>

код

private void StudentsListBox_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
    e.Handled = true;
}
user2490200
источник
-1

Для меня лучшим решением является:

        <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">
                <Setter Property="Focusable" Value="True"/>
                <Setter Property="IsHitTestVisible" Value="False" />
            </Style>
        </ListBox.ItemContainerStyle>
Михал Доброденка
источник
-3

IsEnabled = false

Виктор Евдокимов
источник
2
Это делает все серым, это не то, что я ищу
Shimmy Weitzhandler
1
Но это прямой ответ на простой вопрос :)
Виктор Евдокимов
1
Прямой ответ - это stackoverflow.com/questions/1398559/1398650#1398650 , но все равно спасибо
Shimmy Weitzhandler
Очень помогли мне, я хотел сделать серым и отключенным!
Мартин Робинс
-3

Чтобы отключить один или несколько параметров в списке / раскрывающемся списке, вы можете добавить атрибут «отключен», как показано ниже. Это не дает пользователю выбрать эту опцию, и он получает серый наложение.

ListItem item = new ListItem(yourvalue, yourkey);
item.Attributes.Add("disabled","disabled");
lb1.Items.Add(item);
Hallgeir Engen
источник
В этот раз вы получили высокую оценку и ответили на вопрос WPF с помощью решения ASP.NET.