Tidak ada ListBox.SelectionMode = “Tidak Ada”, apakah ada cara lain untuk menonaktifkan seleksi di listbox?

189

Bagaimana cara menonaktifkan pilihan di ListBox?

Shimmy Weitzhandler
sumber
1
Bisakah Anda memberikan contoh di mana sah untuk memiliki ListBox yang tidak dapat Anda pilih? Karena perilaku utamanya adalah memilih item. Saya mungkin akan memilih cara lain untuk menampilkannya. (Ini bukan saya yang mencoba menjadi seorang kritikus tetapi lebih pada minat yang tulus di mana ini mungkin terjadi)
Marthin
3
@ Martin: misalnya jika Anda ingin menyeret konten dari listboxitem - dalam hal ini Anda mungkin tidak tertarik memilih item itu. JUGA: ketika menyeret item: item yang dipilih dari perubahan listbox saat Anda menyeret dalam listbox - lihat posting ini stackoverflow.com/questions/7589142/…
Danield
1
Saya percaya alasan Shimmy ingin menggunakan ListBox adalah bahwa si penanya dapat membuat listbox dapat dipilih kapan-kapan. Pertanyaan itu juga berharga bagi saya. Katakanlah Anda sedang membangun permainan kartu bermain. Anda dapat memilih satu kartu dari kartu Anda, kadang-kadang, Anda dapat memilih beberapa kartu dan di waktu lain, Anda tidak dapat memilih salah satu.
Gqqnbig
1
Plus, kadang-kadang Anda memiliki 10 kartu dan hanya 4 yang dapat dipilih. Di antara 4, Anda dapat memilih hingga 3.
Gqqnbig
1
@Marthin: Ketika Anda memiliki GridView di ListBox. Header Gridview menyediakan banyak fungsi yang tidak tersedia di tempat lain. Dan Anda memiliki kontrol edit di sel-sel tampilan grid.
Robin Davies

Jawaban:

264

Pendekatan 1 - ItemsControl

Kecuali Anda membutuhkan aspek lain dari itu ListBox, Anda dapat menggunakannya ItemsControlsebagai gantinya. Ini menempatkan item dalam ItemsPaneldan tidak memiliki konsep seleksi.

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

Secara default, ItemsControltidak mendukung virtualisasi elemen turunannya. Jika Anda memiliki banyak item, virtualisasi dapat mengurangi penggunaan memori dan meningkatkan kinerja, dalam hal ini Anda dapat menggunakan pendekatan 2 dan gaya ListBox, atau menambahkan virtualisasi ke AndaItemsControl .

Pendekatan 2 - Gaya ListBox

Atau, cukup gaya ListBox sehingga seleksi tidak terlihat.

<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
sumber
24
tidak, itu hanya akan mengubah efek visual, bukan perilaku seleksi yang sebenarnya
Thomas Levesque
8
Saran pertama saya adalah menggunakan ItemsControl. Apakah kamu melewatkan itu? :)
Drew Noakes
5
Membaca kembali komentar-komentar ini lagi saya ingin menunjukkan bahwa komentar @Thomas Levesque hanya berlaku untuk pendekatan kedua yang saya tunjukkan. Menggunakan plain ItemsControlakan sepenuhnya menghilangkan konsep seleksi apa pun.
Drew Noakes
1
Solusi ItemsControl menghapus dukungan menggulir kotak (scrollbar dan roda mouse).
MuiBienCarlota
1
+1 untuk Pendekatan 1 - ItemsControl. Jika kita memiliki halaman besar yang harus kita gulir, jika pengguna mouse di atas ListBox, itu secara efektif menonaktifkan MouseWheel ketika kotak daftar mengambil peristiwa MouseWheel. Ini berarti bahwa pengguna merasa frustrasi bahwa roda mouse yang digunakan untuk menggulirkan seluruh halaman akan berhenti bekerja secara acak, tergantung pada apakah mouse berada di atas kotak daftar atau tidak.
Contango
159

Saya menemukan solusi yang sangat sederhana dan lurus ke depan bekerja untuk saya, saya harap itu akan berhasil juga untuk Anda

<ListBox ItemsSource="{Items}">
    <ListBox.ItemContainerStyle>
       <Style TargetType="{x:Type ListBoxItem}">
           <Setter Property="Focusable" Value="False"/>
       </Style>
    </ListBox.ItemContainerStyle>
</ListBox>
Asad Durrani
sumber
Saya pikir dia telah melaluinya dengan cukup baik di sini: asaddurrani.wordpress.com/tag/wpf-listbox-disable-selection
Sid
3
Ini sempurna. itu mencegah item yang dipilih dan kontrol lain seperti tombol masih berfungsi. persis apa yang saya cari
Franck
1
+1 untuk pendekatan ini. Jika kita memiliki halaman besar yang harus kita gulir, jika pengguna mouse di atas ListBox, itu secara efektif menonaktifkan MouseWheel ketika kotak daftar mengambil peristiwa MouseWheel. Ini berarti bahwa pengguna merasa frustrasi bahwa roda mouse yang digunakan untuk menggulirkan seluruh halaman akan berhenti bekerja secara acak, tergantung pada apakah mouse berada di atas kotak daftar atau tidak.
Contango
Luar biasa. Pendekatan serupa juga bekerja untuk saya ketika saya membutuhkan tombol pada item untuk tidak menyebabkan pemilihan item - tetapi hanya jika area lain dari item diklik. Cukup atur tombolnya Focusable = "False"!
Jony Adamit
1
Tambahkan properti tambahan ini untuk menghapus sorotan mouseover juga: <Setter Property="IsHitTestVisible" Value="False" />
DonBoitnott
25

Anda dapat beralih menggunakan ItemsControlbukan ListBox. An ItemsControltidak memiliki konsep seleksi, jadi tidak ada yang perlu dimatikan.

Wilka
sumber
2
Menawan Saya tidak pernah tahu Anda bisa langsung mendeklarasikan ItemsControl, saya pikir ini virtual (MustOverride), terima kasih !!!
Shimmy Weitzhandler
Tetapi apakah ItemsControl masih membuat item saya dalam satu baris?
Chry Cheng
@Cry ya itu akan, dan di samping itu, Anda selalu dapat secara manual mengatur ItemTemplate.
Shimmy Weitzhandler
2
Ini pada akhirnya kehilangan terlalu banyak fungsi - misalnya, menggulir.
Jeff
@ Jeff Anda dapat membungkus ItemsControl di ScrollViewer untuk mendapatkan scrolling.
Wilka
12

Opsi lain yang layak dipertimbangkan adalah menonaktifkan ListBoxItems. Ini dapat dilakukan dengan mengatur ItemContainerStyle seperti yang ditunjukkan pada cuplikan berikut.

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

Jika Anda tidak ingin teks menjadi abu-abu, Anda dapat menentukan warna yang dinonaktifkan dengan menambahkan kuas ke sumber daya gaya dengan tombol berikut: {x: Static SystemColors.GrayTextBrushKey}. Solusi lain adalah menimpa templat kontrol ListBoxItem.

Caleb Vear
sumber
Sederhana dan berhasil, terima kasih! Dan itu berlaku di WP 8.1 Runtime juga.
Malutek
8

Ini juga akan berfungsi, jika saya harus menggunakan listbox alih-alih itemscontrol, tetapi saya hanya menampilkan item yang tidak boleh dipilih, saya menggunakan:

<ListBox.ItemContainerStyle>
    <Style TargetType="ListBoxItem">
        <Setter Property="IsHitTestVisible" Value="False" />
    </Style>
</ListBox.ItemContainerStyle>
Andrej Kikelj
sumber
3

Jawaban yang cukup bagus di sini, tetapi saya mencari sesuatu yang sedikit berbeda: Saya ingin seleksi, tetapi tidak ingin ditampilkan (atau ditampilkan dalam masalah yang berbeda).

Solusi di atas tidak bekerja untuk saya (sepenuhnya), jadi saya melakukan sesuatu yang lain: Saya menggunakan gaya baru untuk listbox saya, yang sepenuhnya mengubah template:

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

Dimulai dengan itu, Anda dapat dengan mudah menambahkan sorotan pilihan Anda sendiri, atau membiarkannya seperti itu jika Anda tidak menginginkannya sama sekali.

Andreas Kahler
sumber
2

Sementara jawaban @Drew Noakes adalah solusi cepat untuk sebagian besar kasus, ada sedikit cacat yang datang dengan mengatur x: sikat statis.

Ketika Anda mengatur x: sikat statis seperti yang disarankan, semua anak-anak kontrol dalam item kotak daftar akan mewarisi gaya ini.

Itu berarti bahwa, sementara ini akan berfungsi untuk menonaktifkan penyorotan item kotak daftar, itu dapat mengakibatkan efek yang tidak diinginkan untuk kontrol anak.

Sebagai contoh, jika Anda memiliki ComboBox di dalam ListBoxItem Anda, itu akan menonaktifkan mouse selama penyorotan dalam ComboBox.

Alih-alih, pertimbangkan untuk mengatur VisualStates untuk acara yang Dipilih, Tidak Terpilih, dan MouseOver sebagaimana dicakup dalam solusi yang disebutkan dalam untaian stackoverflow ini: Hapus Sorotan Kontrol Dari ListBoxItem tetapi bukan kontrol anak-anak .

-Frinny

Frinavale
sumber
2

Saya mengusulkan solusi lain. Cukup templat ulang ListBoxItemmenjadi tidak lebih dari ContentPresenter, seperti ...

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

Alasan saya untuk pendekatan ini adalah sebagai berikut:

  1. Dalam kasus saya, saya tidak ingin menonaktifkan interaksi pengguna dengan konten saya ListBoxItemssehingga solusi untuk mengatur IsEnabledtidak akan berfungsi untuk saya.

  2. Solusi lain yang mencoba untuk menata ulang gaya ListBoxItemdengan menimpa properti terkait warna hanya berfungsi untuk kasus-kasus di mana Anda yakin template menggunakan properti tersebut. Itu bagus untuk gaya default, tetapi tidak cocok dengan gaya khusus.

  3. Solusi yang menggunakan ItemsControlistirahat terlalu banyak hal-hal lain sebagai ItemsControlmemiliki tampilan yang sama sekali berbeda dari standar ListBoxdan tidak mendukung virtualisasi, artinya Anda harus tetap kembali template ItemsPanel.

Di atas tidak mengubah tampilan default ListBox, tidak menonaktifkan item dalam templat data untuk ListBox, mendukung virtualisasi secara default, dan bekerja secara independen dari gaya apa pun yang mungkin atau mungkin tidak digunakan dalam aplikasi Anda. Itu prinsip CIUMAN.

Mark A. Donohoe
sumber
1

Catatan: Solusi ini tidak menonaktifkan pemilihan dengan navigasi keyboard atau mengklik kanan (mis. Tombol panah diikuti oleh tombol spasi)

Semua jawaban sebelumnya menghapus kemampuan pilih secara lengkap (tidak ada pergantian runtime) atau cukup hapus efek visual, tetapi bukan pilihan.

Tetapi bagaimana jika Anda ingin dapat memilih dan menunjukkan pilihan dengan kode, tetapi tidak dengan input pengguna? Mungkin Anda ingin "membekukan" pilihan pengguna tanpa menonaktifkan seluruh Listbox?

Solusinya adalah dengan membungkus seluruh ItemsContentTemplate menjadi Button yang tidak memiliki chrome visual. Ukuran tombol harus sama dengan ukuran Item, sehingga sepenuhnya tertutup. Sekarang gunakan tombol IsEnabled-Property:

Aktifkan tombol untuk "membekukan" status Pemilihan item. Ini berfungsi karena tombol yang diaktifkan memakan semua peristiwa mouse sebelum mereka menggelembung ke ListboxItem-Eventhandler. Emplate ItemDataTemplate Anda masih akan menerima MouseEvents karena itu bagian dari konten tombol.

Nonaktifkan tombol untuk mengaktifkan perubahan pilihan dengan mengklik.

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

Mungkin Anda hanya membutuhkan fungsionalitas ItemsControl? Itu tidak memungkinkan seleksi:

<ItemsControl ItemsSource="{Binding Prop1}" ItemTemplate="{StaticResource DataItemsTemplate}" />
Sasha
sumber
3
@ Kimmy: Adalah umum untuk jawaban yang sepele untuk serupa. Tidak ada duplikasi di sini yang layak untuk bendera apa pun. Jika Anda memiliki pertanyaan lain tentang ini, silakan tanyakan di Meta Stack Overflow .
0

Anda dapat menempatkan Textblock di atas kotak daftar Anda, itu tidak akan mengubah tampilan aplikasi Anda dan juga tidak akan memungkinkan untuk memilih item apa pun.

Paras
sumber
1
Anda masih harus menonaktifkan navigasi tab.
Amanduh
0

Perbaikan sederhana yang berfungsi pada Windows Phone misalnya adalah pada pengaturan pilihan item yang dipilih ke nol:

    <ListBox SelectionChanged="ListBox_SelectionChanged">

Dan dalam kode di belakang:

    private void ListBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
    {
        (sender as ListBox).SelectedItem = null;
    }
Jason94
sumber
0

Saya menemukan cara yang sempurna.
Set ListBox IsHitTestVisible menjadi false sehingga pengguna tidak dapat mengarahkan mouse atau gulir ke bawah atau gulir ke atas.
Capture PreviewGotKeyboardFocus e.Handled = true sehingga pengguna dapat memilih item dengan keyboard Tab, Panah atas, Panah bawah.

Keuntungan cara ini:

  1. Item ListBox Foreground tidak akan menjadi Gray.
  2. Latar Belakang ListBox dapat diatur ke Transparan

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>

kode

private void StudentsListBox_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
    e.Handled = true;
}
pengguna2490200
sumber
-1

Bagi saya solusi terbaik adalah:

        <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">
                <Setter Property="Focusable" Value="True"/>
                <Setter Property="IsHitTestVisible" Value="False" />
            </Style>
        </ListBox.ItemContainerStyle>
Michal Dobrodenka
sumber
-3

IsEnabled = false

Viktor Jevdokimov
sumber
2
Itu membuat semuanya menjadi abu-abu, ini bukan yang saya cari
Shimmy Weitzhandler
1
Tapi itu jawaban langsung untuk pertanyaan langsung :)
Viktor Jevdokimov
1
Jawaban lurus ke depan adalah stackoverflow.com/questions/1398559/1398650#1398650 ini , tetapi terima kasih
Shimmy Weitzhandler
Sangat membantu bagi saya, saya ingin berwarna abu-abu dan cacat!
Martin Robins
-3

Untuk menonaktifkan satu atau lebih opsi di listbox / dropdown Anda, Anda dapat menambahkan atribut "dinonaktifkan" seperti yang ditunjukkan di bawah ini. Ini mencegah pengguna untuk memilih opsi ini, dan mendapat hamparan abu-abu.

ListItem item = new ListItem(yourvalue, yourkey);
item.Attributes.Add("disabled","disabled");
lb1.Items.Add(item);
Hallgeir Engen
sumber
Waktu itu Anda mendapat tinggi dan menjawab pertanyaan WPF dengan solusi ASP.NET.