Форум программистов, компьютерный форум, киберфорум
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.52/25: Рейтинг темы: голосов - 25, средняя оценка - 4.52
1 / 1 / 1
Регистрация: 27.05.2015
Сообщений: 86
1
WPF

Создание custom user control на примере Combobox+checkbox

10.12.2019, 10:31. Показов 4711. Ответов 6

Author24 — интернет-сервис помощи студентам
Доброго времени суток, форумчане.
недавно в теме (Кастомный контрол ListBox с CheckBox в качестве элементов) поднимал вопрос о создании выпадающего списка элементов, с возможностью их выбирать и получать коллекцию выбранных элементов. Вопрос решился использованием элемента Expander, однако появился интерес "изобрести своё колесо", а именно таки добить тему с использованием комбобокса с чекбоксами.

Итак суть вопроса: необходимо сделать кастомный юзерконтрол, в котором будет комбобокс, с выпадающим списком чекбоксов. элементы контрола будут содержать два поля: string значение и bool, отвечающее за то выбран элемент галочкой или нет.

имеется следующий код:
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
<UserControl x:Class="StandManager.Views.UserControls.ComboCheckBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:StandManager.Views.UserControls"
             mc:Ignorable="d" 
             Name="comboCheckBox"
             d:DesignHeight="60" d:DesignWidth="200">
    <Grid>
        <StackPanel>
            <ComboBox x:Name="ccb" ItemsSource="{Binding AllItems, ElementName=comboCheckBox}" 
                      SelectedIndex="0"
                      Height="20">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <CheckBox IsChecked="{Binding AllItems/IsChecked, ElementName=comboCheckBox}" 
                                  Content="{Binding AllItems/Content, ElementName=comboCheckBox}" />
                        </StackPanel>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
            
            <!--в этот текстбокс для отладки выводится количество элементов AllItems, который выводится по сути в "главном" комбобоксе-->
            <TextBox Text="{Binding AllItems.Count, ElementName=comboCheckBox, Mode=OneWay}" Height="20"/>
            <!--этот комбобокс нужен для отладки, чтобы убедиться, что сам по себе контрол работает и привязка обычных не сложных свойств к нему тоже работает-->
            <!--StringItems по сути коллекция string элементов значений из коллекции AllItems-->
            <ComboBox Height="20" 
                      ItemsSource="{Binding StringItems, ElementName=comboCheckBox}"
                      SelectedIndex="0"/>
        </StackPanel>
    </Grid>
</UserControl>

и вот его codebehind
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
public partial class ComboCheckBox : UserControl
    {
        public ComboCheckBox()
        {
            InitializeComponent();
        }
 
        public ObservableCollection<ItemChecked> AllItems
        {
            get
            {
                return (ObservableCollection<ItemChecked>)GetValue(AllItemsProperty);
            }
            set
            {
                SetValue(AllItemsProperty, value);
            }
        }
        public static readonly DependencyProperty AllItemsProperty =
            DependencyProperty.Register("AllItems", typeof(ObservableCollection<ItemChecked>), typeof(ComboCheckBox));
 
        public bool IsSelected
        {
            get
            {
                return (bool)GetValue(IsSelectedProperty);
            }
            set
            {
                SetValue(IsSelectedProperty, value);
            }
        }
        public static readonly DependencyProperty IsSelectedProperty =
            DependencyProperty.Register("IsSelected", typeof(bool), typeof(ComboCheckBox));
 
 
        public class ItemChecked : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
            protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
 
            ItemChecked(string content)
            {
                Content = content;
            }
            ItemChecked()
            {
            }
 
            private string _content;
            public string Content
            {
                get => _content;
                set => _content = value;
            }
 
 
            private bool _isChecked;
            public bool IsChecked
            {
                get => _isChecked;
                set => _isChecked = value;
            }
        }
        
        public ObservableCollection<string> StringItems
        {
            get
            {
                return (ObservableCollection<string>)GetValue(StringItemsProperty);
            }
            set
            {
                SetValue(StringItemsProperty, value);
            }
        }
        public static readonly DependencyProperty StringItemsProperty =
            DependencyProperty.Register("StringItems", typeof(ObservableCollection<string>), typeof(ComboCheckBox));
 
 
 
 
        public object MyProperty
        {
            get
            {
                return (object)GetValue(MyPropertyProperty);
            }
            set
            {
                SetValue(MyPropertyProperty, value);
            }
        }
        public static readonly DependencyProperty MyPropertyProperty =
            DependencyProperty.Register("MyProperty", typeof(object), typeof(ComboCheckBox));
}
Во вью модели
есть вот такое свойство, которое должно привязываться к AllItems.
C#
1
2
3
4
5
6
7
8
9
10
ObservableCollection<FIOWorkers> _workers = new ObservableCollection<FIOWorkers>();
        public ObservableCollection<FIOWorkers> ClassWorkersHS_FIO
        {
            get => _workers;
            set
            {
                _workers = value;
                OnPropertyChanged();
            }
        }
FIOWorkers - точно такой же класс, как и ItemChecked из кодбихайнда контрола.

В итоге не работает привязка к свойству AllItems. Эта коллекция оказывается пустой.
Есть следующее замечание: когда делаю привязку НЕ к свойству AllItems, а к свойству object MyProperty, то на вьюшке в контроле выпадает список чекбоксов, но пустых.
Хотелось бы разобраться почему контрол по итогу не работает.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
10.12.2019, 10:31
Ответы с готовыми решениями:

Какая разница между Web server control, Composite control и User Control
Подскажите, пожалуйста, какая разница между Web server control, Composite control и User Control, а...

Custom Control не появляется в toolbar
Здравствуйте. Сделал пользовательский контрол создавая Windows Form Control Library. При попытке...

Custom Control, наследующий от Panel
Добрый вечер, под web никогда не работал, возник вопрос. Пишу custom control, наследующий от Panel,...

Manifest файл на Custom Control
Всем привет. Меня интересует следующий вопрос: Есть кустомный Edit контрол. Подключив Manifest...

6
1577 / 583 / 183
Регистрация: 05.12.2015
Сообщений: 935
11.12.2019, 11:19 2
Лучший ответ Сообщение было отмечено tagota как решение

Решение

работающий пример.
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
<UserControl x:Class="gz.Controls.ComboCheckBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             x:Name="uc" mc:Ignorable="d"              
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid DataContext="{Binding ElementName=uc}">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding CheckedItems.Count, StringFormat='отмеченo: {0}'}" Margin="6,0"/>
            <ComboBox x:Name="box" ItemsSource="{Binding Items}" MinWidth="100">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <CheckBox Checked="syncTest" Unchecked="syncTest" IsChecked="{Binding IsChecked}" VerticalAlignment="Center" Margin="2,0"/>
                            <TextBlock  Text="{Binding content}" />
                        </StackPanel>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
            <ComboBox ItemsSource="{Binding CheckedItems}" MinWidth="100">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding content}"/>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
            <TextBlock Text="{Binding ElementName=box, Path=SelectedItem.content}" Margin="6,0"/>            
        </StackPanel>
    </Grid>
</UserControl>
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
namespace gz.Controls
{
    public partial class ComboCheckBox : UserControl
    {
        public ComboCheckBox()
        {
            InitializeComponent();
        }
        public ObservableCollection<object> CheckedItems { get; } = new ObservableCollection<object> ();
        public ObservableCollection<object> Items
        {
            get { return (ObservableCollection<object>) GetValue( ItemsProperty ); }
            set { SetValue( ItemsProperty, value ); }
        }
        public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register( "Items", typeof( ObservableCollection<object> ), typeof( ComboCheckBox ), new PropertyMetadata( null, itemschanged ) );
        private static void itemschanged( DependencyObject d, DependencyPropertyChangedEventArgs e )        
        {            (d as ComboCheckBox).syncTest( null, null );        }
        internal void syncTest( object sender, EventArgs e )
        {
            CheckedItems.Clear();
            if ( Items == null ) return;
            foreach ( FIOWorker w in Items )
                if ( w.IsChecked )
                    CheckedItems.Add( w );
        }
    }
    class FIOWorker
    {
        public string content { get; set; }
        public bool IsChecked { get; set; }
    }
}
использовать через привязку к Items. Отмеченные элементы будут в CheckedItems.
1
1 / 1 / 1
Регистрация: 27.05.2015
Сообщений: 86
11.12.2019, 15:37  [ТС] 3
proa33, мда, у меня скоро истерический смех начнётся... не работает. Комбобокс пустой
Вас не сильно затруднит весь проект скинуть?
0
1577 / 583 / 183
Регистрация: 05.12.2015
Сообщений: 935
11.12.2019, 19:09 4
Лучший ответ Сообщение было отмечено tagota как решение

Решение

сократил немного
выбор по клику на CheckBox, а не элементе
Вложения
Тип файла: zip test.zip (12.1 Кб, 48 просмотров)
1
1 / 1 / 1
Регистрация: 27.05.2015
Сообщений: 86
12.12.2019, 14:35  [ТС] 5
proa33, спасибо за помощь!
Конкретно в чём у меня ошибка я пока так и не разобрался, но первое, в чём косяк, это то, что коллекция должна быть ObservableCollection<object>, а не FIOWorkers. Потому что, если в Вашем примере делаю коллекцию не object, то ситуация абсолютно такая же , как у меня: коллекция не отображается.
Ну а дальше уже буду разбираться и смотреть, что да как.
0
1577 / 583 / 183
Регистрация: 05.12.2015
Сообщений: 935
12.12.2019, 15:28 6
Цитата Сообщение от tagota Посмотреть сообщение
в чём у меня ошибка я пока так и не разобралс
разберитесь с DataContext
это очень скользкая тема в которой многие путаются
если до конца не разберетесь с этим - "загадочные" ошибки будут постоянно
1
1 / 1 / 1
Регистрация: 27.05.2015
Сообщений: 86
13.12.2019, 11:13  [ТС] 7
proa33, Да, с пониманием датаконтекста есть вопросы, буду тестить. Спасибо!
0
13.12.2019, 11:13
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
13.12.2019, 11:13
Помогаю со студенческими работами здесь

Как использовать Custom Control?
нашел код такого ComboBox http://smfd.ru/blog/wpf-filtered-combobox создал класс с этим кодом....

GridView Web Custom Control
Как переопределить Edit button для GridView в Web Custom Control, чтобы вместо линка отображался...

View Picklist Custom Control
Добрый день. Ребята, нужна ваша помощь или совет. решил у себя сделать кнопку пиклист. Для...

Обращение к полям Xpage из Custom Control
Может кто уже заморачивался, как реализовать аналог подформы на XPages? Но не в плане Data Binding...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru