Nie ma ListBox.SelectionMode = „Brak”, czy istnieje inny sposób wyłączenia wyboru w polu listy?

189

Jak mogę wyłączyć zaznaczenie w ListBox?

Shimmy Weitzhandler
źródło
1
Czy możesz podać przykład, w którym można mieć ListBox, z którego nie można wybrać? Ponieważ głównym zachowaniem jest wybieranie przedmiotów. Prawdopodobnie wybrałbym inny sposób, aby to pokazać. (To nie ja staram się być krytykiem, ale szczerze interesuję się tym, gdzie może się to zdarzyć)
Marthin
3
@ Martin: na przykład, jeśli chcesz przeciągnąć zawartość z elementu listy - w tym przypadku prawdopodobnie nie jesteś zainteresowany wyborem tego elementu. RÓWNIEŻ: podczas przeciągania elementu: wybrany element listy zmienia się podczas przeciągania w polu listy - zobacz ten post stackoverflow.com/questions/7589142/...
Danield
1
Uważam, że powodem, dla którego Shimmy chce używać ListBox, jest to, że pytający może w pewnym momencie wybrać pole listy. To pytanie jest również dla mnie cenne. Załóżmy, że budujesz grę w karty. Możesz wybrać jedną kartę ze swoich kart, czasem możesz wybrać wiele, a innym razem nie możesz wybrać żadnej.
Gqqnbig,
1
Ponadto czasami masz 10 kart i tylko 4 z nich można wybierać. Wśród 4 możesz wybrać do 3.
Gqqnbig,
1
@Marthin: Gdy masz GridView w ListBox. Nagłówki Gridview zapewniają wiele funkcji niedostępnych gdzie indziej. I masz kontrolki edycji w komórkach widoku siatki.
Robin Davies,

Odpowiedzi:

264

Podejście 1 - ItemsControl

O ile nie potrzebujesz innych aspektów ListBox, możesz ItemsControlzamiast tego użyć . Umieszcza przedmioty w ItemsPaneli nie ma pojęcia wyboru.

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

Domyślnie ItemsControlnie obsługuje wirtualizacji jego elementów potomnych. Jeśli masz wiele elementów, wirtualizacja może zmniejszyć zużycie pamięci i poprawić wydajność, w takim przypadku możesz zastosować podejście 2 i stylizować ListBoxlub dodać wirtualizację do swojegoItemsControl .

Podejście 2 - Stylizacja ListBox

Alternatywnie po prostu nadaj stylu ListBox tak, aby zaznaczenie nie było widoczne.

<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>
Drew Noakes
źródło
24
nie, zmieni jedynie efekt wizualny, a nie faktyczne zachowanie selekcji
Thomas Levesque,
8
Moją pierwszą sugestią było użycie ItemsControl. Tęskniłeś za tym? :)
Drew Noakes,
5
Ponownie czytając te komentarze, chcę podkreślić, że komentarz @Thomas Levesque dotyczy tylko drugiego podejścia, które pokazuję. Użycie zwykłego ItemsControlcałkowicie usunie każdą koncepcję selekcji.
Drew Noakes,
1
Rozwiązanie ItemsControl usuwa obsługę przewijania pola (pasek przewijania i kółko myszy).
MuiBienCarlota
1
+1 za podejście 1 - ItemsControl. Jeśli mamy ogromną stronę, którą musimy przewinąć, jeśli użytkownik najedzie myszką na ListBox, to skutecznie wyłączy MouseWheel, gdy lista będzie przechwytywać zdarzenia MouseWheel. Oznacza to, że użytkownik jest sfrustrowany, że kółko myszy używane do przewijania całej strony losowo przestanie działać, w zależności od tego, czy wskaźnik myszy znajduje się nad polem listy, czy nie.
Contango,
159

Znalazłem bardzo proste i proste rozwiązanie, które działa dla mnie, mam nadzieję, że przydałoby się również Tobie

<ListBox ItemsSource="{Items}">
    <ListBox.ItemContainerStyle>
       <Style TargetType="{x:Type ListBoxItem}">
           <Setter Property="Focusable" Value="False"/>
       </Style>
    </ListBox.ItemContainerStyle>
</ListBox>
Asad Durrani
źródło
Myślę, że całkiem dobrze sobie z tym poradził
Sid
3
To jest doskonałe. zapobiega wybranemu elementowi i innym elementom sterującym, takim jak przyciski, nadal działa. dokładnie to, czego szukałem
Franck
1
+1 za to podejście. Jeśli mamy ogromną stronę, którą musimy przewinąć, jeśli użytkownik najedzie myszką na ListBox, to skutecznie wyłączy MouseWheel, gdy lista będzie przechwytywać zdarzenia MouseWheel. Oznacza to, że użytkownik jest sfrustrowany, że kółko myszy używane do przewijania całej strony losowo przestanie działać, w zależności od tego, czy wskaźnik myszy znajduje się nad polem listy, czy nie.
Contango,
Doskonały. Podobne podejście działało również dla mnie, gdy potrzebowałem przycisków na przedmiotach, aby nie powodować wyboru przedmiotu - ale tylko wtedy, gdy kliknięto inny obszar przedmiotu. Wystarczy ustawić przyciski Focusable = "False"!
Jony Adamit
1
Dodaj tę dodatkową właściwość, aby również usunąć wyróżnienie <Setter Property="IsHitTestVisible" Value="False" />
kursora
25

Możesz przełączyć się na używanie ItemsControlzamiast zamiast ListBox. Nie ItemsControlma pojęcia selekcji, więc nie ma się co wyłączać.

Wilka
źródło
2
Uroczy. Nigdy nie wiedziałem, że możesz bezpośrednio zadeklarować ItemsControl, myślałem, że to wirtualny (MustOverride), dzięki !!!
Shimmy Weitzhandler,
Ale czy ItemsControl nadal renderuje moje przedmioty w jednym wierszu?
Chry Cheng,
@Chry tak, tak, a ponadto zawsze można ręcznie ustawić ItemTemplate.
Shimmy Weitzhandler
2
W rezultacie traci się zbyt wiele funkcji - np. Przewijanie.
Jeff
@Jeff możesz owinąć ItemsControl w ScrollViewer, aby uzyskać przewijanie.
Wilka
12

Inną opcją wartą rozważenia jest wyłączenie ListBoxItems. Można to zrobić, ustawiając ItemContainerStyle, jak pokazano w poniższym fragmencie.

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

Jeśli nie chcesz, aby tekst był szary, możesz określić wyłączony kolor, dodając pędzel do zasobów stylu za pomocą następującego klucza: {x: Static SystemColors.GrayTextBrushKey}. Innym rozwiązaniem byłoby zastąpienie szablonu kontrolnego ListBoxItem.

Caleb Vear
źródło
Prosty i działający, dzięki! Dotyczy to również WP 8.1 Runtime.
Malutek
8

To również zadziała, jeśli będę musiał użyć pola listy zamiast kontroli przedmiotów, ale po prostu wyświetlę elementy, których nie można wybrać, używam:

<ListBox.ItemContainerStyle>
    <Style TargetType="ListBoxItem">
        <Setter Property="IsHitTestVisible" Value="False" />
    </Style>
</ListBox.ItemContainerStyle>
Andrej Kikelj
źródło
3

Dość dobre odpowiedzi tutaj, ale szukałem czegoś nieco innego: chcę selekcji, ale po prostu nie chcę, aby była pokazywana (lub pokazywana w innej sprawie).

Powyższe rozwiązania nie działały dla mnie (całkowicie), więc zrobiłem coś innego: użyłem nowego stylu dla mojego listbox, który całkowicie redefiniuje szablony:

<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>

Zaczynając od tego, możesz łatwo dodać własne zaznaczenie wyboru lub zostawić tak, jeśli w ogóle nie chcesz.

Andreas Kahler
źródło
2

Podczas gdy odpowiedź @Drew Noakes jest szybkim rozwiązaniem w większości przypadków, istnieje pewna wada związana z ustawieniem pędzli x: Static.

Po ustawieniu pędzli x: Static zgodnie z sugestią wszystkie elementy podrzędne w elemencie pola listy odziedziczą ten styl.

Oznacza to, że chociaż będzie to działać w celu wyłączenia podświetlenia elementu listy, może to powodować niepożądane efekty dla elementów podrzędnych.

Na przykład, jeśli masz ComboBox w swoim ListBoxItem, to wyłączy to mysz nad podświetlaniem w ComboBox.

Zamiast tego zastanów się nad ustawieniem VisualStates dla zdarzeń Selected, Unselected i MouseOver zgodnie z rozwiązaniem wymienionym w tym wątku: „ Usuń wyróżnienie kontrolki z ListBoxItem, ale nie kontrolki potomne .

-Frinny

Frinavale
źródło
2

Proponuję jeszcze jedno rozwiązanie. Po prostu ponownie szablon, ListBoxItemaby był niczym więcej ContentPresenter, jak ...

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

Moje powody takiego podejścia są następujące:

  1. W moim przypadku nie chcę wyłączać interakcji użytkownika z zawartością mojego, ListBoxItemswięc ustawione rozwiązanie IsEnablednie będzie dla mnie działać.

  2. Inne rozwiązanie, które próbuje zmienić styl ListBoxItem, zastępując właściwości związane z kolorem, działa tylko w tych przypadkach, w których masz pewność, że szablon używa tych właściwości. To jest w porządku dla stylów domyślnych, ale zrywa ze stylami niestandardowymi.

  3. Rozwiązania, które wykorzystują ItemsControlzłamanie zbyt wielu innych rzeczy, ponieważ ItemsControlmają zupełnie inny wygląd niż standard ListBoxi nie obsługują wirtualizacji, co oznacza, że ​​i tak musisz ponownie utworzyć szablon ItemsPanel.

Powyższe nie zmienia domyślnego wyglądu ListBox, nie wyłącza elementów w szablonach danych dla ListBox, domyślnie obsługuje wirtualizację i działa niezależnie od stylów, które mogą być lub nie być używane w Twojej aplikacji. To zasada KISS.

Mark A. Donohoe
źródło
1

Uwaga: to rozwiązanie nie wyłącza wyboru poprzez nawigację na klawiaturze lub kliknięcie prawym przyciskiem (tj. Klawisze strzałek, a następnie klawisz spacji)

Wszystkie poprzednie odpowiedzi albo całkowicie usuwają wybór zdolności (bez przełączania w czasie wykonywania), albo po prostu usuwają efekt wizualny, ale nie wybór.

Ale co jeśli chcesz mieć możliwość wyboru i pokazania wyboru według kodu, ale nie na podstawie danych wprowadzonych przez użytkownika? Może chcesz „zamrozić” wybór użytkownika, nie wyłączając całego Listbox?

Rozwiązaniem jest zawinięcie całego ItemsContentTemplate w przycisk, który nie ma wizualnego chromu. Rozmiar przycisku musi być równy rozmiarowi przedmiotu, więc jest całkowicie zakryty. Teraz użyj właściwości IsEnabled przycisku:

Włącz przycisk, aby „zamrozić” stan zaznaczenia elementu. Działa to, ponieważ włączony przycisk zjada wszystkie zdarzenia myszy, zanim zostaną one bąbelkowane do modułu obsługi ListboxItem-Event. Twój ItemsDataTemplate nadal będzie otrzymywać MouseEvents, ponieważ jest częścią zawartości przycisków.

Wyłącz przycisk, aby włączyć zmianę zaznaczenia, klikając.

<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
źródło
1

Może potrzebujesz tylko funkcjonalności ItemsControl? Nie pozwala na wybór:

<ItemsControl ItemsSource="{Binding Prop1}" ItemTemplate="{StaticResource DataItemsTemplate}" />
Sasha
źródło
3
@Shimmy: Trywialne odpowiedzi są podobne. Nie ma tu powielania godnego żadnej flagi. Jeśli masz więcej pytań na ten temat, zadaj pytanie na temat Meta Stack Overflow .
0

Możesz umieścić blok tekstu nad listą, nie zmieni to wyglądu twojej aplikacji, a także nie pozwoli wybrać żadnego elementu.

Paras
źródło
1
Jednak nadal musisz wyłączyć nawigację po kartach.
Amanduh
0

Prosta poprawka, która działa na przykład na Windows Phone, polega na ustawieniu zaznaczenia wybranego elementu na zero:

    <ListBox SelectionChanged="ListBox_SelectionChanged">

A w kodzie za:

    private void ListBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
    {
        (sender as ListBox).SelectedItem = null;
    }
Jason94
źródło
0

Znalazłem idealny sposób.
Ustaw ListBox IsHitTestVisible na wartość false, aby użytkownik nie mógł najechać myszą, przewinąć w dół ani w górę.
Przechwyć PreviewGotKeyboardFocus e.Handled = true, aby użytkownik mógł wybrać element za pomocą klawiatury, Strzałka w górę, Strzałka w dół.

Zaleta w ten sposób:

  1. Elementy ListBox Pierwszy plan nie zmieni się na szary.
  2. Tło ListBox można ustawić na Przezroczyste

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>

kod

private void StudentsListBox_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
    e.Handled = true;
}
użytkownik2490200
źródło
-1

Dla mnie najlepszym rozwiązaniem jest:

        <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">
                <Setter Property="Focusable" Value="True"/>
                <Setter Property="IsHitTestVisible" Value="False" />
            </Style>
        </ListBox.ItemContainerStyle>
Michał Dobrodenka
źródło
-3

IsEnabled = false

Viktor Jevdokimov
źródło
2
Sprawia, że ​​robi się cały szary, nie tego szukam
Shimmy Weitzhandler,
1
Ale to prosta odpowiedź na proste pytanie :)
Viktor Jevdokimov
1
Prostą odpowiedzią jest to stackoverflow.com/questions/1398559/1398650#1398650 , ale i tak dzięki
Shimmy Weitzhandler
Bardzo mi pomógł, chciałem wyszarzyć i wyłączyć!
Martin Robins,
-3

Aby wyłączyć jedną lub więcej opcji w liście / menu rozwijanym, możesz dodać atrybut „disabled”, jak pokazano poniżej. Zapobiega to wybraniu tej opcji przez użytkownika i uzyskuje szarą nakładkę.

ListItem item = new ListItem(yourvalue, yourkey);
item.Attributes.Add("disabled","disabled");
lb1.Items.Add(item);
Hallgeir Engen
źródło
Tym razem osiągnąłeś poziom wysoki i odpowiedziałeś na pytanie WPF rozwiązaniem ASP.NET.