ListBox.SelectionMode = “None” yoktur, liste kutusundaki seçimi devre dışı bırakmanın başka bir yolu var mı?


189

Liste Kutusundaki seçimi nasıl devre dışı bırakabilirim?


1
Seçim yapabileceğiniz bir ListBox'a sahip olmanın geçerli olduğu bir örnek verebilir misiniz? Ana davranış öğeleri seçmek olduğundan. Muhtemelen onu sergilemek için başka bir yol seçerdim. (Bu benim eleştirmen olmaya değil, bunun gerçekleşebileceği yere gerçek bir ilgi göstermeye çalışıyor)
Marthin

3
@Martin: örneğin, içeriği bir liste kutusundan sürüklemek istiyorsanız - bu durumda muhtemelen bu öğeyi seçmek istemezsiniz. AYRICA: bir öğeyi sürüklerken: liste
kutusunun

1
Shimmy'nin ListBox'ı kullanmak istemesinin sebebinin, askerin liste kutusunu bazen seçilebilir yapabileceğine inanıyorum. Soru da benim için değerlidir. Diyelim ki bir oyun kartı oyunu inşa ediyorsunuz. Kartlarınızdan bir kart seçebilirsiniz, bazen birden fazla kart seçebilir ve diğer zamanlarda kart seçemezsiniz.
Gqqnbig

1
Ayrıca, bazen 10 kartınız vardır ve bunlardan sadece 4 tanesi seçilebilir. 4 arasında 3'e kadar seçim yapabilirsiniz.
Gqqnbig

1
@Marthin: Bir ListBox içinde bir GridView olduğunda. Gridview üstbilgileri başka yerde bulunmayan birçok işlevsellik sağlar. Ve gridview hücrelerinde düzenleme denetimleri var.
Robin Davies

Yanıtlar:


264

Yaklaşım 1 - ItemsControl

Bunun diğer yönlerine ihtiyacınız olmadığı sürece ListBoxkullanabilirsiniz ItemsControl. Öğeleri yerleştirir ItemsPanelve seçim kavramına sahip değildir.

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

Varsayılan olarak, ItemsControlalt öğelerinin sanallaştırılmasını desteklemez. Çok sayıda öğeniz varsa, sanallaştırma bellek kullanımını azaltabilir ve performansı artırabilir; bu durumda yaklaşım 2'yi kullanabilir ve stilinizi biçimlendirebilirListBox veya bilgisayarınıza sanallaştırma ekleyebilirsinizItemsControl .

Yaklaşım 2 - Stil ListBox

Alternatif olarak, ListBox'ı seçim görünmeyecek şekilde biçimlendirin.

<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
Hayır, yalnızca görsel efekti değiştirecek, gerçek seçim davranışını değiştirmeyecek
Thomas Levesque

8
İlk önerim ItemsControl kullanmaktı. Bunu özledin mi? :)
Drew Noakes

5
Bu yorumları tekrar okurken @Thomas Levesque'in yorumunun yalnızca gösterdiğim ikinci yaklaşım için geçerli olduğunu belirtmek istiyorum. Plain kullanmak ItemsControl, seçim konseptini tamamen kaldıracaktır.
Drew Noakes

1
ItemsControl çözümü kutu kaydırma desteğini (kaydırma çubuğu ve fare tekerleği) çıkarır.
MuiBienCarlota

1
Yaklaşım 1 için +1 - ItemsControl. Kaydırmamız gereken devasa bir sayfamız varsa, kullanıcı bir ListBox'ın üzerine fareyle gelirse, liste kutusu MouseWheel olaylarını yakaladığı için MouseWheel'ı etkin bir şekilde devre dışı bırakır. Bu, kullanıcının tüm sayfayı kaydırmak için kullanılan fare tekerleğinin, farenin bir liste kutusunun üzerinde olup olmamasına bağlı olarak rastgele çalışmasının durduracağı anlamına gelir.
Contango

159

Benim için çalışan çok basit ve basit bir çözüm buldum, umarım sizin için de işe yarar

<ListBox ItemsSource="{Items}">
    <ListBox.ItemContainerStyle>
       <Style TargetType="{x:Type ListBoxItem}">
           <Setter Property="Focusable" Value="False"/>
       </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

Sanırım burada oldukça iyi geçti: asaddurrani.wordpress.com/tag/wpf-listbox-disable-selection
Sid

3
Bu harika. seçilen öğenin ve düğmeler gibi diğer kontrollerin hala çalışmasını önler. tam olarak aradığım şey
Franck

1
Bu yaklaşım için +1. Kaydırmamız gereken devasa bir sayfamız varsa, kullanıcı bir ListBox'ın üzerine fareyle gelirse, liste kutusu MouseWheel olaylarını yakaladığı için MouseWheel'ı etkili bir şekilde devre dışı bırakır. Bu, kullanıcının tüm sayfayı kaydırmak için kullanılan fare tekerleğinin, farenin bir liste kutusunun üzerinde olup olmamasına bağlı olarak rastgele çalışmasının durduracağı anlamına gelir.
Contango

Mükemmel. Öğe seçimine neden olmamak için öğeler üzerinde düğmelere ihtiyaç duyduğumda da aynı yaklaşım benim için çalıştı - ancak yalnızca öğenin diğer alanı tıklandığında. Sadece düğmeleri ayarlayın Focusable = "False"!
Jony Adamit

1
Fareyle üzerine gelme vurgulamasını da kaldırmak için bu ek özelliği ekleyin: <Setter Property="IsHitTestVisible" Value="False" />
DonBoitnott

25

Yerine bir ItemsControlyerine geçebilirsiniz ListBox. An'ın ItemsControlseçim kavramı yoktur, bu yüzden kapatmak için hiçbir şey yoktur.


2
Büyüleyici. Doğrudan ItemsControl ilan edebileceğini bilmiyordum, bunun sanal olduğunu düşündüm (MustOverride), teşekkürler !!!
Shimmy Weitzhandler

Peki ItemsControl hala eşyalarımı tek bir satırda oluşturuyor mu?
Chry Cheng

@Chry evet olurdu ve buna ek olarak, her zaman manuel olarak ayarlayabilirsiniz ItemTemplate.
Shimmy Weitzhandler

2
Bu, çok fazla işlevsellik kaybına neden olur - örn. Kaydırma.
Jeff

@Jeff kaydırma yapmak için ItemsControl'ü ScrollViewer'a sarabilirsiniz.
Wilka

12

Dikkate değer başka bir seçenek ListBoxItems devre dışı bırakmaktır. Bu, aşağıdaki snippet'te gösterildiği gibi ItemContainerStyle ayarlanarak yapılabilir.

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

Metnin gri olmasını istemiyorsanız, stilin kaynaklarına şu tuşla bir fırça ekleyerek devre dışı bırakılan rengi belirleyebilirsiniz: {x: Static SystemColors.GrayTextBrushKey}. Diğer çözüm, ListBoxItem denetim şablonunu geçersiz kılmak olacaktır.


Basit ve çalışıyor, teşekkürler! Ve WP 8.1 Runtime'da da geçerlidir.
Malutek

8

Bu aynı zamanda, itemscontrol yerine liste kutusu kullanmanız gerekiyorsa, ancak sadece seçilmemesi gereken öğeleri görüntülüyorum, kullanacağım:

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

3

Burada oldukça iyi cevaplar, ama biraz farklı bir şey arıyordum: Seçim istiyorum, ama sadece gösterilmesini (veya farklı bir konuda gösterilmesini) istemiyorum.

Yukarıdaki çözümler benim için (tamamen) işe yaramadı, bu yüzden başka bir şey yaptım: Liste kutum için şablonları tamamen yeniden tanımlayan yeni bir stil kullandım:

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

Bundan başlayarak, kendi seçiminizi kolayca vurgulayabilir veya hiç istemiyorsanız böyle bırakabilirsiniz.


2

@Drew Noakes'ın cevabı çoğu durumda hızlı bir çözüm olsa da, x: Statik fırçaların ayarlanmasıyla birlikte gelen bir miktar kusur var.

X: Statik fırçaları önerildiği gibi ayarladığınızda, liste kutusu öğesindeki tüm alt denetimler bu stili devralır.

Bu, liste kutusu öğesinin vurgulanmasını devre dışı bırakmak için çalışırken, alt denetimler için istenmeyen etkilere neden olabileceği anlamına gelir.

Örneğin, ListBoxItem içinde bir ComboBox varsa, ComboBox içinde vurgulamak için fareyi devre dışı bırakır.

Bunun yerine, VisualStates'i Seçili, Seçili Olmayan ve MouseOver olayları için bu yığın akışı iş parçacığında belirtilen çözümde kapsanan şekilde ayarlamayı düşünün: Denetim Vurgulamasını ListBoxItem'den kaldırın, ancak alt denetimler değil .

-Frinny


2

Yine başka bir çözüm öneriyorum. Sadece bir şablondan ListBoxItembaşka bir şey olmayacak şekilde yeniden ContentPresenter...

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

Bu yaklaşımın nedenleri şunlardır:

  1. Benim durumumda, kullanıcı içeriğimin içeriğiyle etkileşimini devre dışı bırakmak istemiyorum, ListBoxItemsbu nedenle ayarlanacak çözüm benim IsEnablediçin işe yaramayacak.

  2. ListBoxItemRenkle ilgili özellikleri geçersiz kılarak yeniden stil vermeye çalışan diğer çözüm, yalnızca şablonun bu özellikleri kullandığından emin olduğunuz örneklerde çalışır. Bu, varsayılan stiller için iyidir, ancak özel stillerle kırılır.

  3. Standarttan tamamen farklı bir görünüme sahip olduğu ve sanallaştırmayı desteklemediği için çok daha fazla ItemsControlşey kullanan çözümler , yine de yeniden şablon yapmanız gerekiyor .ItemsControlListBoxItemsPanel

Yukarıdakilerin varsayılan görünümünü değiştirmez, ListBoxiçin veri şablonlarındaki öğeleri devre dışı bırakmaz ListBox, varsayılan olarak sanallaştırmayı destekler ve uygulamanızda kullanılmakta olan veya kullanılmayan stillerden bağımsız olarak çalışır. Bu KISS prensibi.


1

Not: Bu çözüm, klavye gezinmesi veya sağ tıklama ile seçimi devre dışı bırakmaz (örn. Ok tuşları ve ardından boşluk tuşu) ile

Önceki tüm yanıtlar ya seçme özelliğini tamamen kaldırır (çalışma zamanında geçiş yapmaz) ya da görsel efekti kaldırır, ancak seçimi kaldırmaz.

Peki ya seçimi kullanıcı koduna göre değil, koda göre seçmek ve göstermek istiyorsanız? Tüm Liste Kutusunu devre dışı bırakmazken kullanıcının seçimini "dondurmak" isteyebilirsiniz?

Çözüm, tüm ItemsContentTemplate'i görsel krom içermeyen bir Düğme içine sarmaktır. Düğmenin boyutu Öğenin boyutuna eşit olmalıdır, bu yüzden tamamen kaplıdır. Şimdi düğmenin IsEnabled-Property özelliğini kullanın:

Öğenin Seçim durumunu "dondurmak" için düğmeyi etkinleştirin. Etkinleştirilen düğme, ListboxItem-Eventhandler öğesine gelmeden önce tüm fare olaylarını yediği için çalışır. ItemsDataTemplate öğeniz, düğmeler içeriğinin bir parçası olduğu için MouseEvents almaya devam edecektir.

Öğesini tıklayarak seçimi değiştirmeyi etkinleştirmek için düğmeyi devre dışı bırakın.

<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


1

Belki de sadece ItemsControl işlevselliğine ihtiyacınız var? Seçime izin vermiyor:

<ItemsControl ItemsSource="{Binding Prop1}" ItemTemplate="{StaticResource DataItemsTemplate}" />

3
@Shimmy: Önemsiz cevapların benzer olması yaygındır. Burada herhangi bir bayrağa layık hiçbir kopya yoktur. Bununla ilgili başka sorularınız varsa lütfen Meta Stack Overflow ile ilgili soru sorun .

0

Liste kutunuzun üzerine bir Textblock yerleştirebilirsiniz, uygulamanızın görünümünü değiştirmez ve ayrıca herhangi bir öğenin seçilmesine izin vermez.


1
Yine de sekme gezinmesini devre dışı bırakmanız gerekir.
Amanduh

0

Örneğin, Windows Phone'da çalışan basit bir düzeltme, seçilen öğeyi null olarak ayarlamakla ilgilidir:

    <ListBox SelectionChanged="ListBox_SelectionChanged">

Ve arkasındaki kodda:

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

0

Mükemmel bir yol buldum.
ListBox IsHitTestVisible öğesini false olarak ayarlayın, böylece kullanıcı fareyle üzerine gelemez veya sayfayı aşağı veya yukarı kaydıramaz.
PreviewGotKeyboardFocus e.Handled = true öğesini yakalayın, böylece kullanıcı klavye Sekmesi, Yukarı ok, Aşağı ok tuşlarıyla öğeyi seçebilir.

Bu şekilde avantaj:

  1. ListBox öğeleri Ön Plan Gri olmayacak.
  2. ListBox Arkaplanı Saydam olarak ayarlanabilir

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

-1

Benim için en iyi çözüm:

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


-3

Liste kutunuzda / açılır listenizdeki bir veya daha fazla seçeneği devre dışı bırakmak için "devre dışı" özelliğini aşağıda gösterildiği gibi ekleyebilirsiniz. Bu, kullanıcının bu seçeneği seçmesini önler ve gri bir kaplama alır.

ListItem item = new ListItem(yourvalue, yourkey);
item.Attributes.Add("disabled","disabled");
lb1.Items.Add(item);

O zaman yüksek ve bir ASP.NET çözümü ile bir WPF sorusunu yanıtladı.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.