powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / Бага в Selector'е (ListBox и т.д.)
1 сообщений из 1, страница 1 из 1
Бага в Selector'е (ListBox и т.д.)
    #39304518
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
View:
Обычный ListBox (выделение Single), элементы ListBoxItem имею стиль с привязкой поля IsSelected к соответствующему полю для Person, обычный TextBox для фильтрации и 3 TextBlock (они на суть дела не влияют)
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ControlGridExample"
        x:Class="ControlGridExample.MainWindow"
        Title="MainWindow" Height="640" Width="1024"
        FontSize="14"
        DataContext="{StaticResource MainModel}">
    <Window.Resources>
        <DataTemplate x:Key="PersonTemplate" DataType="{x:Type local:Person}">
            <TextBlock>
                <TextBlock.Inlines>
                    <Run Text="{Binding Name, Mode=OneWay}"/>
                    <Run Text=" - "/>
                    <Run Text="{Binding Age, Mode=OneWay}"/>
                </TextBlock.Inlines>
            </TextBlock>
        </DataTemplate>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="IsSelected" Value="{Binding IsSelected}"/>
        </Style>
    </Window.Resources>
    <DockPanel>
        <TextBox DockPanel.Dock="Top" Margin="5" Text="{Binding FilterString, UpdateSourceTrigger=PropertyChanged}"/>
        
        <StackPanel DockPanel.Dock="Bottom" Margin="5">
            <TextBlock Text="{Binding SelectionMode, ElementName=PART_ListBox}"/>
            <ContentPresenter Content="{Binding SelectedItem, ElementName=PART_ListBox}"
                              ContentTemplate="{StaticResource PersonTemplate}"/>
            <TextBlock Text="{Binding SelectedIndex, ElementName=PART_ListBox}"/>
        </StackPanel>
        
        <ListBox x:Name="PART_ListBox" ItemsSource="{Binding Persones}"
                 ItemTemplate="{StaticResource PersonTemplate}"
                 Margin="5"/>

    </DockPanel>
</Window>



ViewModel:
3 класса BaseViewModel, MainModel и Person
Ни чего особенного, просто класс со списком Persones, состоящим из <Person>, свойством FilterString и т.д.

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
    public class MainModel : BaseViewModel
    {
        private string _filterString;
        private readonly ICollectionView _view;

        public MainModel()
        {
            Persones = new ObservableCollection<Person>
            {
                new Person("Roman", 33),
                new Person("Anastasia", 37),
                new Person("Adolf", 32),
                new Person("Ivan", 45)
            };
            _view = CollectionViewSource.GetDefaultView(Persones);
            _view.Filter = OnFilter;
        }

        private bool OnFilter(object obj)
        {
            if (string.IsNullOrEmpty(_filterString)) return true;
            var person = obj as Person;
            return person == null || person.Name.ToLowerInvariant().Contains(_filterString.ToLowerInvariant());
        }

        public ObservableCollection<Person> Persones { get; }

        public string FilterString
        {
            set
            {
                _filterString = value;
                _view?.Refresh();
            }
            get
            {
                return _filterString;
                
            }
        }
    }

    public class Person : BaseViewModel
    {
        private bool _isSelected;
        
        public Person(string name, int age)
        {
            Name = name;
            Age = age;
        }
        public string Name { get; }
        public int Age { get; }

        public bool IsSelected
        {
            set
            {
                if (_isSelected == value) return;
                Debug.Print($"IsSelected changed: {Name}, {value}");
                _isSelected = value;
                OnPropertyChanged(nameof(IsSelected));
            }
            get
            {
                return _isSelected;
                
            }
        }
    }

    public abstract class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }



Как повторить баг:
Выделяем 4ый элемент списка (Dmitriy), и сразу переходим в строку фильтрации. В строке фильтрации вводим букву "R"
все элементы кроме 1ого будут отфильтрованы (включая выделенный элемент)
Теперь выделяем 1ый (единственный) элемент (Roman) и удаляем букву R из фильтра и получаем вот такую картину:

Выделение Single, после этого снять выделение с Roman можно только либо через Ctrl+LeftClick или выделить другой элемент и потянуть выделение наверх. Если нажимать на сам элемент, реакции не будет...

Ноги у проблемы растут в Binding'е IsSelected.
Код: xml
1.
2.
3.
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="IsSelected" Value="{Binding IsSelected}"/>
        </Style


Когда мы фильтруем элементы, они исчезают из ListBox и фармально Listbox'у о них ни чего не известно, когда мы выделяем другой элемент, старый выделенный элемент в списке отсутствует и ListBox не снимает с него выделения. Так как со старого элемента выделение не снялось, то и в свойстве ViewModel оно осталось прежним.
А когда мы удаляем фильтрации, ранее выделенный элемент становится видимым, и так как в модели для него IsSelected = True, он тоже выглядит выделенным.
Если убрать Binding то при фильтрации выделение сбрасывается, а это мне совсем не нужно.

Вот сижу я и думаю, что мне теперь с этим говном делать.
...
Рейтинг: 0 / 0
1 сообщений из 1, страница 1 из 1
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / Бага в Selector'е (ListBox и т.д.)
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]