Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
725 views
in Technique[技术] by (71.8m points)

c# - WPF ComboBox with checkboxes and textbox with search field

I have gone through this thread

Looking for a WPF ComboBox with checkboxes and tried to include TextBox in the DataTemplate but not able to view the TextBox on running the application. I have created a UserControl as follows

<UserControl x:Class="MyProj.UserControls.MultiSelectComboBox"
         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"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<ComboBox
    x:Name="MultiSelectCombo"  
    SnapsToDevicePixels="True"
    OverridesDefaultStyle="True"
    ScrollViewer.HorizontalScrollBarVisibility="Auto"
    ScrollViewer.VerticalScrollBarVisibility="Auto"
    ScrollViewer.CanContentScroll="True"
    IsSynchronizedWithCurrentItem="True"
                       >
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
              **<TextBlock Text="{Binding Text, Mode=TwoWay}" Tag="{RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}"
                   Width="100" />**
                <CheckBox Content="{Binding Text}"
                      IsChecked="{Binding Path=IsSelected, Mode=TwoWay}"
                      Tag="{RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}"
                       Click="CheckBox_Click" Width="20"          />
            </StackPanel>
        </DataTemplate>
    </ComboBox.ItemTemplate>
    <ComboBox.Template>
        <ControlTemplate TargetType="ComboBox">
            <Grid >

                <ToggleButton 
                    x:Name="ToggleButton" 
                   Grid.Column="2" IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
                    Focusable="false"                           
                    ClickMode="Press" HorizontalContentAlignment="Left" >
                    <ToggleButton.Template>
                        <ControlTemplate>
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="18"/>
                                </Grid.ColumnDefinitions>
                                <Border
              x:Name="Border" 
              Grid.ColumnSpan="2"
              CornerRadius="2"
              Background="White"
              BorderBrush="Silver"
              BorderThickness="1,1,1,1" />
                                <Border 
                x:Name="BorderComp" 
              Grid.Column="0"
              CornerRadius="2" 
              Margin="1" 
             Background="White"
              BorderBrush="Black"
              BorderThickness="0,0,0,0" >
                                    <TextBlock Text="{Binding Path=Text,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" 
                                           Background="White" Padding="3" />
                                </Border>
                                <Path 
              x:Name="Arrow"
              Grid.Column="1"     
              Fill="Black"
              HorizontalAlignment="Center"
              VerticalAlignment="Center"
              Data="M 0 0 L 4 4 L 8 0 Z"/>
                            </Grid>
                        </ControlTemplate>
                    </ToggleButton.Template>
                </ToggleButton>
                <Popup 
                    Name="Popup"
                    Placement="Bottom"                        
                    AllowsTransparency="True" 
                    Focusable="False"  IsOpen="{TemplateBinding IsDropDownOpen}"
                    PopupAnimation="Slide">
                    <Grid 
                              Name="DropDown"
                              SnapsToDevicePixels="True"  
                        MinWidth="{TemplateBinding ActualWidth}"
                              MaxHeight="{TemplateBinding MaxDropDownHeight}">
                        <Border 
                                x:Name="DropDownBorder"
                               BorderThickness="1" Background="White"
                                BorderBrush="Black"/>
                        <ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True" DataContext="{Binding}">
                            <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
                        </ScrollViewer>
                    </Grid>
                </Popup>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="HasItems" Value="false">
                    <Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
                </Trigger>
                <Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
                    <Setter TargetName="DropDownBorder" Property="CornerRadius" Value="4"/>
                    <Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </ComboBox.Template>
</ComboBox>

and here is the code

     using System;
    using System.Collections.ObjectModel;
    using System.Windows;
    using System.Windows.Controls;
    using System.Linq;
    using System.Collections.Generic;
    using System.Text;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;

    namespace MyProj.UserControls
    {
        /// <summary>
        /// Interaction logic for MultiSelectComboBox.xaml
        /// </summary>
    public partial class MultiSelectComboBox : UserControl
    {
        private ObservableCollection<Node> _nodeList;

        public MultiSelectComboBox()
        {
            InitializeComponent();
            _nodeList = new ObservableCollection<Node>();
        }

        #region Dependency Properties

        public event EventHandler CheckBoxClick;

        public static readonly DependencyProperty ItemsSourceProperty =
             DependencyProperty.Register("ItemsSource", typeof(Lexicon<string, int>), typeof(MultiSelectComboBox), new FrameworkPropertyMetadata(null,
        new PropertyChangedCallback(OnItemsSourceChanged)));

        public static readonly DependencyProperty SelectedItemsProperty =
         DependencyProperty.Register("SelectedItems", typeof(Lexicon<string, int>), typeof(MultiSelectComboBox), new FrameworkPropertyMetadata(null,
     new PropertyChangedCallback(OnSelectedItemsChanged)));

        public static readonly DependencyProperty TextProperty =
           DependencyProperty.Register("Text", typeof(string), typeof(MultiSelectComboBox), new UIPropertyMetadata(string.Empty));

        public static readonly DependencyProperty DefaultTextProperty =
            DependencyProperty.Register("DefaultText", typeof(string), typeof(MultiSelectComboBox), new UIPropertyMetadata(string.Empty));



        public Lexicon<string, int> ItemsSource
        {
            get { return (Lexicon<string, int>)GetValue(ItemsSourceProperty); }
            set
            {
                SetValue(ItemsSourceProperty, value);
            }
        }

        public Lexicon<string, int> SelectedItems
        {
            get { return (Lexicon<string, int>)GetValue(SelectedItemsProperty); }
            set
            {
                SetValue(SelectedItemsProperty, value);
            }
        }

        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        public string DefaultText
        {
            get { return (string)GetValue(DefaultTextProperty); }
            set { SetValue(DefaultTextProperty, value); }
        }
        #endregion

        #region Events
        private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MultiSelectComboBox control = (MultiSelectComboBox)d;
            control.DisplayInControl();
        }

        private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MultiSelectComboBox control = (MultiSelectComboBox)d;
            control.SelectNodes();
            control.SetText();
        }

        private void CheckBox_Click(object sender, RoutedEventArgs e)
        {
            CheckBox clickedBox = (CheckBox)sender;

            if (clickedBox.Content.ToString() == "All")
            {
                if (clickedBox.IsChecked.Value)
                {
                    foreach (Node node in _nodeList)
                    {
                        node.IsSelected = true;
                    }
                }
                else
                {
                    foreach (Node node in _nodeList)
                    {
                        node.IsSelected = false;
                    }
                }

            }
            else
            {
                int _selectedCount = 0;
                foreach (Node s in _nodeList)
                {
                    if (s.IsSelected && s.Text != "All")
                        _selectedCount++;
                }
                if (_selectedCount == _nodeList.Count - 1)
                    _nodeList.FirstOrDefault(i => i.Text == "All").IsSelected = true;
                else
                    _nodeList.FirstOrDefault(i => i.Text == "All").IsSelected = false;
            }
            SetSelectedItems();
            SetText();
            if (this.CheckBoxClick != null)
                this.CheckBoxClick(this, e);

        }
        #endregion


        #region Methods
        private void SelectNodes()
        {
            foreach (KeyValuePair<string, int> keyValue in SelectedItems)
            {
                Node node = _nodeList.FirstOrDefault(i => i.Text == keyValue.Key);
                if (node != null)
                    node.IsSelected = true;
            }
        }

        private void SetSelectedItems()
        {
            if (SelectedItems == null)
                SelectedItems = new Lexicon<string, int>();
            SelectedItems.Clear();
            foreach (Node node in _nodeList)
            {
                if (node.IsSelected && node.Text != "All")
                {
                    if (this.ItemsSource.Count > 0)

                        SelectedItems.Add(node.Text, node.Id);
                }
            }
        }

        //private void DisplayInControl()
        //{
        //    _nodeList.Clear();

        //    foreach (KeyValuePair<string, int> keyValue in this.ItemsSource)
        //    {
        //        Node node = null;
        //        if (this.ItemsSource.Count == 1)
        //            node = new Node(keyValue.Key);

        //        else
        //        

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Modify the ScrollViewer element in the ControlTemplate to include a TextBox:

<Popup 
    Name="Popup"
    Placement="Bottom"                        
    AllowsTransparency="True" 
    Focusable="False"  IsOpen="{TemplateBinding IsDropDownOpen}"
    PopupAnimation="Slide">
    <Grid 
        Name="DropDown"
        SnapsToDevicePixels="True"  
        MinWidth="{TemplateBinding ActualWidth}"
        MaxHeight="{TemplateBinding MaxDropDownHeight}">
        <Border 
            x:Name="DropDownBorder"
            BorderThickness="1" Background="White"
            BorderBrush="Black"/>
        <ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True" DataContext="{Binding}">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <TextBox />
                <StackPanel Grid.Row="1" IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
            </Grid>
        </ScrollViewer>
    </Grid>
</Popup>

You don't need any TextBox in the ItemTemplate.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...