Nano Hash - криптовалюты, майнинг, программирование

ListBox с одним выбором, а также отменой выбора при щелчке?

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

Выбор / отмена выбора реализуется в списке (с SelectionMode = "Single"), когда вы удерживаете crtl, но, к сожалению, никто из моих пользователей не должен знать об этом.

С SelectionMode = "Multiple" у нас есть точная функциональность, которую я хочу, за исключением того, что вы можете выбрать более одного элемента ...

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

Для этого я использовал список с расширяющимся содержимым. Чтобы помочь расширению, я сделал в левой части элемента списка треугольник, который указывает вправо, когда он не раскрыт, который поворачивается, чтобы указывать вниз, когда вы выбрали элемент списка.

Итак, сначала пользователь видит список над установками, а затем, когда он выбрал нужный элемент, выбрав его, элемент списка расширяется до остальной информации, которую ему нужно ввести. Это довольно приятно и работает хорошо, но тестирование сообщает, что они хотят, чтобы второй щелчок по треугольнику снял выделение (и, таким образом, свернул развернутый раздел). И я должен признать, что я тоже нажал ¤% & стрелку, ожидая, что действие приведет к коллапсу ... :-(

Кто-нибудь знает, как этого можно достичь (желательно без кода)?


Ответы:


1

Попробуй это:

вы используете ToggleButton как «расширитель» подробного содержимого. Свойство IsChecked кнопки-переключателя можно привязать к свойству IsSelected элемента.

вот код:

<ListBox SelectionMode="Single">
   <ListBox.ItemsSource>
      <x:Array Type="{x:Type sys:String}">
         <sys:String>test1</sys:String>
         <sys:String>test2</sys:String>
         <sys:String>test3</sys:String>
         <sys:String>test4</sys:String>
         <sys:String>test5</sys:String>
         <sys:String>test6</sys:String>
      </x:Array>
   </ListBox.ItemsSource>
   <ListBox.ItemTemplate>
      <DataTemplate>
         <StackPanel Orientation="Horizontal">
            <ToggleButton IsChecked="{Binding 
                          RelativeSource={RelativeSource FindAncestor, 
                          AncestorType={x:Type ListBoxItem}},
                          Path=IsSelected}"
            >btn</ToggleButton>
         </StackPanel>
      </DataTemplate>
   </ListBox.ItemTemplate>
</ListBox>

как это работает: В списке можно выбрать только один элемент. Когда мы выбираем элемент, Toggler расширяется, потому что его IsChecked привязан к ListBoxItem.IsSelected (ListBoxItem - это элемент управления, который оборачивается вокруг содержимого каждого элемента) его родительского ListBoxItem. Поскольку selectionMode является одиночным, как только выбирается другой элемент, происходит следующее:

  • Отменить выделение фактически выбранного элемента
  • Через привязку тумблер тоже снимается
  • Выберите новый элемент
  • Переключатель новых элементов проверяется через привязку

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

28.02.2011
  • У меня нет проблемы с расширением при выборе, проблема в том, чтобы сделать так, чтобы в списке выбирался только один элемент за раз, и чтобы отменить выбор при втором щелчке. 28.02.2011
  • но он делает именно это. on togglebuttonclick разворачивается и выбирает элемент. при втором щелчке он сворачивается и отменяет выбор элемента. и выбран максимум 1 элемент. Хитрость заключается в двусторонней привязке к свойству IsSelected объекта ListBoxItem. просто попробуйте 28.02.2011
  • Я поправляюсь, вы правы, и решение гениальное. Спасибо! Я должен сказать, что немного не уверен, как это работает на самом деле? 1. Нажата кнопка-переключатель - ›tb отмечен -› выбран элемент просмотра списка - ›любой другой элемент просмотра списка не выбран 2. tb снова нажат -› флажок tb не отмечен - ›элемент просмотра списка не выбран ... Правильно ли это ставить? 01.03.2011
  • Я отредактировал объяснение внутри ответа. да это именно то 01.03.2011
  • Вы знаете, почему я не могу отменить выбор ListBoxItem с помощью того же ToggleButton. Работает только отбор. 27.02.2014
  • Выглядит неплохо, но как избавиться от кнопки-переключателя, показать настраиваемое содержимое для ListBoxItem (в основном два текстовых блока) и по-прежнему получить результат переключения выбора? 18.11.2014
  • @RomainHautefeuille: просто поместите настраиваемый контент в кнопку переключения. (если у вас есть несколько элементов в стековой панели или аналогичном) 19.11.2014

  • 2

    Обычный способ сделать это - установить для режима SelectionMode значение Multiple, а затем отменить выбор всех элементов, кроме вновь выбранного, в событии SelectionChanged.

    См. Следующие ссылки

    Вот прикрепленное поведение, которое делает это, и его можно использовать следующим образом

    <ListBox local:ListBoxSelectionBehavior.ClickSelection="True"
             ...>
    

    ListBoxSelectionBehavior

    public static class ListBoxSelectionBehavior 
    {
        public static readonly DependencyProperty ClickSelectionProperty = 
            DependencyProperty.RegisterAttached("ClickSelection", 
                                                typeof(bool),
                                                typeof(ListBoxSelectionBehavior),
                                                new UIPropertyMetadata(false, OnClickSelectionChanged));
        public static bool GetClickSelection(DependencyObject obj) 
        {
            return (bool)obj.GetValue(ClickSelectionProperty); 
        }
        public static void SetClickSelection(DependencyObject obj, bool value) 
        {
            obj.SetValue(ClickSelectionProperty, value); 
        }
        private static void OnClickSelectionChanged(DependencyObject dpo, 
                                                                 DependencyPropertyChangedEventArgs e) 
        {
            ListBox listBox = dpo as ListBox;
            if (listBox != null) 
            { 
                if ((bool)e.NewValue == true) 
                {
                    listBox.SelectionMode = SelectionMode.Multiple;
                    listBox.SelectionChanged += OnSelectionChanged;
                } 
                else 
                {
                    listBox.SelectionChanged -= OnSelectionChanged;
                } 
            } 
        }
        static void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.AddedItems.Count > 0)
            {
                ListBox listBox = sender as ListBox;
                var valid = e.AddedItems[0];
                foreach (var item in new ArrayList(listBox.SelectedItems))
                {
                    if (item != valid)
                    {
                        listBox.SelectedItems.Remove(item);
                    }
                }
            }
        }
    }
    
    28.02.2011
  • Мне это решение нравится больше, чем принятое, так как в нем нет хитростей с элементами пользовательского интерфейса. 18.11.2014

  • 3

    Мое решение - установить ListBox SelectionMode на Multiple, добавить метод hibitedSelectionButOne для события Click и после этого разрешить только один выбранный элемент следующим образом:

    Private Sub forbidSelectionButOne(sender As Object, e As MouseButtonEventArgs)
        Dim lv As ListView = TryCast(sender, ListView)
        If lv IsNot Nothing Then
            If lv.SelectedIndex <> getCausesListViewItemIndex(sender, e) Then
                lv.SelectedIndex = getCausesListViewItemIndex(sender, e)
                e.Handled = True
            End If
            lv.Focus()
        End If
    End Sub
    

    И функция помощи в поиске ListViewItem, по которому щелкнули мышью:

    Private Function getCausesListViewItemIndex(ByVal sender As Object, e As RoutedEventArgs) As Integer
        Dim dep As DependencyObject = TryCast(e.OriginalSource, DependencyObject)
        Do While dep IsNot Nothing AndAlso Not TypeOf (dep) Is ListViewItem
            dep = VisualTreeHelper.GetParent(dep)
        Loop
        If dep Is Nothing Then
            Return -1
        Else
            Dim lv As ListView = TryCast(sender, ListView)
            If lv IsNot Nothing Then
                Dim i As Integer = lv.ItemContainerGenerator.IndexFromContainer(dep)
                Return i
            Else
                Return -1
            End If
        End If
    End Function
    
    02.12.2016

    4

    Я позволил себе дополнить ответ Фредрика для UWP и .NET Framework 4.7:

    public static class ListBoxSelectionBehavior
    {
        public static readonly DependencyProperty ClickSelectionProperty =
        DependencyProperty.RegisterAttached("ClickSelection",
                                            typeof(bool),
                                            typeof(ListBoxSelectionBehavior),
                                            new PropertyMetadata(false, OnClickSelectionChanged));
    
        public static bool GetClickSelection(DependencyObject obj)
        {
            return (bool)obj.GetValue(ClickSelectionProperty);
        }
        public static void SetClickSelection(DependencyObject obj, bool value)
        {
            obj.SetValue(ClickSelectionProperty, value);
        }
        private static void OnClickSelectionChanged(DependencyObject dpo, DependencyPropertyChangedEventArgs e)
        {
            if (dpo is ListBox listBox)
            {
                if ((bool)e.NewValue == true)
                {
                    listBox.SelectionMode = SelectionMode.Multiple;
                    listBox.SelectionChanged += OnSelectionChanged;
                }
                else
                {
                    listBox.SelectionChanged -= OnSelectionChanged;
                }
            }
        }
        static void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.AddedItems.Count > 0)
            {
                ListBox listBox = sender as ListBox;
                var valid = e.AddedItems[0];
                foreach (var item in new ArrayList(listBox.SelectedItems.ToArray()))
                {
                    if (item != valid)
                    {
                        listBox.SelectedItems.Remove(item);
                    }
                }
            }
        }
    }
    
    10.12.2018
  • Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, почему и / или как этот код отвечает на вопрос, улучшает его долгосрочную ценность. 10.12.2018

  • 5

    Еще проще - просто добавить флаг в сочетании с SelectionMode = "Multiple".

     private bool _ignoreSelectionFlag = false;
        private void LbHistory_OnSelectionChanged(object sender,SelectionChangedEventArgs e)
        {
            if (_ignoreSelectionFlag)
                return;
    
            if (e.AddedItems.Count > 0)
            {
                ListBox listBox = sender as ListBox;
                var valid = e.AddedItems[0];
    
                _ignoreSelectionFlag = true;
                LbHistory.UnselectAll();
                LbHistory.SelectedItems.Add(e.AddedItems[0]);
                e.Handled = true;
                _ignoreSelectionFlag = false;
    
    
            }
        }
    
    27.02.2019
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..