• 修改Aaron Zhou 的WPF ComboBox 与 MultiComboBox 有感


    用VS2012 Profile 测试发现ComboBox 与 MultiComboBox的数据源OnDataSourceChanged事件中,this.Items.Add()方法被循环调用并且速度很慢,是界面加载的主要瓶颈

    (居然不是访问服务!怒改!)

    原来该对象的每一次变更都会触发OnCollectionChanged事件,并会通知前台界面重新渲染,速度很慢。改用中间变量再一次性赋值就可以了。

    另外,在对MultiComboBox增加输入搜索功能时发现,自定义的依赖属性DataSource,尽管ViewModel中绑定的是ObservableCollection并用TwoWay的方式,只要对象是通过集合的Add/Remove方式改变,就不会获得PropertyChange通知。因为对象的引用并没有变化。

    但默认的ComboBox的ItemSource是可以的。看了源码也终于理解了为什么ComboBox除了ItemSource为什么还要个Items对象。

    原来ItemSource与数据源绑定后同时注册了OnCollectionChanged事件,该事件中会对Items对象重新赋值(一次性赋值),由于ItemSource与ViewModel的对象是同一对象,

    所以不论是直接赋值还是Add/Remove,ItemSource都能捕获到ViewModel数据源的变化。

    另一个改动是MultiComboBox的SelectedItems属性,需要其内部不论是直接赋值还是Add/Remove都要通知到ViewModel的数据源对象。由于不能控制ViewModel的编码,只能每次都重新赋值了

    最后附上可搜索过滤的MultiCombox代码:

      1 using Microsoft.Practices.Prism.Commands;
      2 using Microsoft.Windows.Themes;
      3 using System;
      4 using System.Collections;
      5 using System.Collections.Generic;
      6 using System.Collections.ObjectModel;
      7 using System.Collections.Specialized;
      8 using System.ComponentModel;
      9 using System.Globalization;
     10 using System.Linq;
     11 using System.Text;
     12 using System.Threading.Tasks;
     13 using System.Windows;
     14 using System.Windows.Controls;
     15 using System.Windows.Data;
     16 using System.Windows.Input;
     17 
     18 namespace Common.Controls.CustomControls
     19 {
     20     public class CustomMultipleDropDownBox : ComboBox
     21     {
     22 
     23         #region UI Control Property
     24 
     25         protected ListBox MyListBox
     26         {
     27             get
     28             {
     29                 return base.GetTemplateChild("MyListBox") as ListBox;
     30             }
     31         }
     32 
     33         /// <summary>
     34         /// Gets the text box in charge of the editable portion of the combo box.
     35         /// </summary>
     36         protected TextBox EditableTextBox
     37         {
     38             get
     39             {
     40                 return base.GetTemplateChild("DisPlayTextBlock") as TextBox;
     41             }
     42         }
     43 
     44 
     45         private CheckBox SelectAllCheckBox { get; set; }
     46 
     47         #endregion
     48 
     49         #region Dependency Property
     50         private const string SelectAllItem = "Select All";
     51         private int TotalCount { get; set; }
     52         private List<ComboBoxNode> dataSourceNodeList { get; set; }
     53         public DelegateCommand<ComboBoxNode> CheckBoxSelectCommand { get; set; }
     54         public DelegateCommand ToggleButtonClickCommand { set; get; }
     55 
     56         #region DataSource
     57         public ObservableCollection<ComboBoxNode> NodeList
     58         {
     59             get { return (ObservableCollection<ComboBoxNode>)GetValue(NodeListProperty); }
     60             set { SetValue(NodeListProperty, value); }
     61         }
     62 
     63         public static readonly DependencyProperty NodeListProperty =
     64             DependencyProperty.Register("NodeList", typeof(ObservableCollection<ComboBoxNode>), typeof(CustomMultipleDropDownBox), new PropertyMetadata(null, null));
     65 
     66 
     67         #endregion
     68 
     69         #region SelectedItems && SelectedCount
     70 
     71         private IList m_selectedItemCollection;
     72         protected IList SelectedItemCollection
     73         {
     74             set
     75             {
     76                 m_selectedItemCollection = value;
     77                 if (value != null && m_selectedItemCollection is INotifyCollectionChanged)
     78                 {
     79                     ((INotifyCollectionChanged)m_selectedItemCollection).CollectionChanged
     80                 += new NotifyCollectionChangedEventHandler(OnSelectItemCollectionChanged);
     81                 }
     82             }
     83         }
     84         public IList SelectedItems
     85         {
     86             get { return (IList)GetValue(SelectedItemsProperty); }
     87             set { SetValue(SelectedItemsProperty, value); }
     88         }
     89 
     90         // Using a DependencyProperty as the backing store for SelectedItems.  This enables animation, styling, binding, etc...
     91         public static readonly DependencyProperty SelectedItemsProperty =
     92             DependencyProperty.Register("SelectedItems", typeof(IList), typeof(CustomMultipleDropDownBox), new PropertyMetadata(null, new PropertyChangedCallback(OnSelectedItemsChanged)));
     93 
     94         /// <summary>
     95         /// change selected count when selected items changed
     96         /// </summary>
     97         /// <param name="d"></param>
     98         /// <param name="e"></param>
     99         private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    100         {
    101             CustomMultipleDropDownBox c = d as CustomMultipleDropDownBox;
    102             c.SelectedItemCollection = c.SelectedItems;
    103             if (c.SelectedItems != null && c.SelectedItems.Count == 0)
    104                 c.SelectedCount = null;
    105             else
    106                 c.SelectedCount = c.SelectedItems.Count;
    107 
    108             c.ChangeNodeIsSelectedStatus();
    109         }
    110 
    111         private void OnSelectItemCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    112         {
    113             this.ChangeNodeIsSelectedStatus();
    114         }
    115 
    116         /// <summary>
    117         /// Used to inform IsMandatory trigger how many items has selected
    118         /// </summary>
    119         public int? SelectedCount
    120         {
    121             get { return (int?)GetValue(SelectedCountProperty); }
    122             set { SetValue(SelectedCountProperty, value); }
    123         }
    124 
    125         // Using a DependencyProperty as the backing store for SelectedCount.  This enables animation, styling, binding, etc...
    126         public static readonly DependencyProperty SelectedCountProperty =
    127             DependencyProperty.Register("SelectedCount", typeof(int?), typeof(CustomMultipleDropDownBox), new PropertyMetadata(null, new PropertyChangedCallback(OnSelectedCountChanged)));
    128 
    129         private static void OnSelectedCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    130         {
    131             CustomMultipleDropDownBox c = d as CustomMultipleDropDownBox;
    132 
    133             if (e.NewValue != null && (int)e.NewValue == 0)
    134             {
    135                 c.SelectedCount = null;
    136             }
    137         }
    138         #endregion
    139 
    140         #region SeparateString
    141         public string SeparateString
    142         {
    143             get { return (string)GetValue(SeparateStringProperty); }
    144             set { SetValue(SeparateStringProperty, value); }
    145         }
    146 
    147         // Using a DependencyProperty as the backing store for SelectedItems.  This enables animation, styling, binding, etc...
    148         public static readonly DependencyProperty SeparateStringProperty =
    149             DependencyProperty.Register("SeparateString", typeof(string), typeof(CustomMultipleDropDownBox), new PropertyMetadata(";"));
    150         #endregion
    151 
    152         #region ItemEnabledPath
    153         public string ItemEnabledPath
    154         {
    155             get { return (string)GetValue(ItemEnabledPathProperty); }
    156             set { SetValue(ItemEnabledPathProperty, value); }
    157         }
    158 
    159         // Using a DependencyProperty as the backing store for DropDownHeight.  This enables animation, styling, binding, etc...
    160         public static readonly DependencyProperty ItemEnabledPathProperty =
    161             DependencyProperty.Register("ItemEnabledPath", typeof(string), typeof(CustomMultipleDropDownBox), new PropertyMetadata(null));
    162         #endregion
    163 
    164         #region DropDown Height & Width
    165         public double DropDownHeight
    166         {
    167             get { return (double)GetValue(DropDownHeightProperty); }
    168             set { SetValue(DropDownHeightProperty, value); }
    169         }
    170 
    171         // Using a DependencyProperty as the backing store for DropDownHeight.  This enables animation, styling, binding, etc...
    172         public static readonly DependencyProperty DropDownHeightProperty =
    173             DependencyProperty.Register("DropDownHeight", typeof(double), typeof(CustomMultipleDropDownBox), new PropertyMetadata(0.0));
    174 
    175 
    176         public double DropDownWidth
    177         {
    178             get { return (double)GetValue(DropDownWidthProperty); }
    179             set { SetValue(DropDownWidthProperty, value); }
    180         }
    181 
    182         // Using a DependencyProperty as the backing store for DropDownWidth.  This enables animation, styling, binding, etc...
    183         public static readonly DependencyProperty DropDownWidthProperty =
    184             DependencyProperty.Register("DropDownWidth", typeof(double), typeof(CustomMultipleDropDownBox), new PropertyMetadata(0.0));
    185         #endregion
    186 
    187         #region DisplayText and ToolTip
    188         public string DisplayText
    189         {
    190             get { return (string)GetValue(DisplayTextProperty); }
    191             set { SetValue(DisplayTextProperty, value); }
    192         }
    193 
    194         // Using a DependencyProperty as the backing store for DisplayText.  This enables animation, styling, binding, etc...
    195         public static readonly DependencyProperty DisplayTextProperty =
    196             DependencyProperty.Register("DisplayText", typeof(string), typeof(CustomMultipleDropDownBox), new PropertyMetadata(null, new PropertyChangedCallback(OnDisplayTextChanged)));
    197 
    198         /// <summary>
    199         /// To control tooltip's content and can displayed when this property is changed
    200         /// </summary>
    201         /// <param name="d"></param>
    202         /// <param name="e"></param>
    203         private static void OnDisplayTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    204         {
    205             CustomMultipleDropDownBox c = d as CustomMultipleDropDownBox;
    206 
    207             if (e.NewValue != null)
    208             {
    209                 if (e.NewValue.ToString().Length > c.MaxLength)
    210                 {
    211                     c.DisplayTextToolTip = true;
    212                 }
    213                 else
    214                 {
    215                     c.DisplayTextToolTip = false;
    216 
    217                 }
    218                 c.Text = e.NewValue.ToString();
    219             }
    220             else
    221             {
    222                 c.DisplayTextToolTip = false;
    223                 c.Text = null;
    224             }
    225 
    226         }
    227 
    228         /// <summary>
    229         /// Set whether tooltip can displayed
    230         /// </summary>
    231         public bool DisplayTextToolTip
    232         {
    233             get { return (bool)GetValue(DisplayTextToolTipProperty); }
    234             set { SetValue(DisplayTextToolTipProperty, value); }
    235         }
    236 
    237         // Using a DependencyProperty as the backing store for DisplayTextToolTip.  This enables animation, styling, binding, etc...
    238         public static readonly DependencyProperty DisplayTextToolTipProperty =
    239             DependencyProperty.Register("DisplayTextToolTip", typeof(bool), typeof(CustomMultipleDropDownBox), new PropertyMetadata(false));
    240 
    241         public int MaxLength
    242         {
    243             get { return (int)GetValue(MaxLengthProperty); }
    244             set { SetValue(MaxLengthProperty, value); }
    245         }
    246 
    247         // Using a DependencyProperty as the backing store for MaxLength.  This enables animation, styling, binding, etc...
    248         public static readonly DependencyProperty MaxLengthProperty =
    249             DependencyProperty.Register("MaxLength", typeof(int), typeof(CustomMultipleDropDownBox), new PropertyMetadata(0));
    250 
    251         #endregion
    252 
    253 
    254         #endregion
    255 
    256         #region construtor
    257         static CustomMultipleDropDownBox()
    258         {
    259             DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomMultipleDropDownBox), new FrameworkPropertyMetadata(typeof(CustomMultipleDropDownBox)));
    260 
    261         }
    262         public CustomMultipleDropDownBox()
    263         {
    264             this.DropDownWidth = 400;
    265             this.DropDownHeight = 150;
    266             this.MaxLength = 30;
    267             this.DisplayTextToolTip = false;
    268             TextCompositionManager.StartComposition(new TextComposition(InputManager.Current, this.EditableTextBox,string.Empty));
    269             CheckBoxSelectCommand = new DelegateCommand<ComboBoxNode>(CheckBoxClickCommandProcess);
    270             ToggleButtonClickCommand = new DelegateCommand(ToggleButtonClickCommandProcess);
    271             dataSourceNodeList = new List<ComboBoxNode>();
    272             NodeList = new ObservableCollection<ComboBoxNode>();
    273             this.Loaded += CustomMultipleDropDownBox_Loaded;
    274         }
    275 
    276         private void CustomMultipleDropDownBox_LostFocus(object sender, RoutedEventArgs e)
    277         {
    278             this.IsDropDownOpen = false;
    279         }
    280 
    281         protected override void OnPreviewKeyDown(System.Windows.Input.KeyEventArgs e)
    282         {
    283             if (e.Key == Key.Down)
    284             {
    285                 if (!this.IsDropDownOpen)
    286                 {
    287                     this.DisplayText = null;
    288                     this.NodeList = this.dataSourceNodeList.ToObservableCollection();
    289                     this.IsDropDownOpen = true;
    290                 }
    291                 //e.Handled = true;
    292             }
    293             base.OnPreviewKeyDown(e);
    294         }
    295 
    296         void CustomMultipleDropDownBox_Loaded(object sender, RoutedEventArgs e)
    297         {
    298             try
    299             {
    300                 OnApplyTemplate();
    301                 this.IsEditable = true;
    302 
    303                 if (this.SelectedItems == null || this.SelectedItems.Count == 0)
    304                 {
    305                     this.SelectedCount = null;
    306                 }
    307                 else
    308                 {
    309                     this.SelectedCount = this.SelectedItems.Count;
    310                     this.DisplayText = GetSelectedText();
    311                     if (this.SelectedCount == this.TotalCount)
    312                     {
    313                         this.SelectAllCheckBox.IsChecked = true;
    314                     }
    315                 }
    316             }
    317             catch (Exception)
    318             {
    319 
    320             }
    321         }
    322 
    323         protected override void OnDropDownClosed(EventArgs e)
    324         {
    325             base.OnDropDownClosed(e);
    326             DisplayText = this.GetSelectedText();
    327             var selectedItems = this.dataSourceNodeList.
    328                 FindAll(p => p.IsSelected && p.Title != SelectAllItem).Select(p => p.Item).ToList();
    329             var list = this.SelectedItems.CreateNewInstance();
    330             foreach (var item in selectedItems)
    331             {
    332                 list.Add(item);
    333             }
    334             this.SelectedItems = list;
    335         }
    336 
    337         //protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
    338         //{
    339         //    base.OnItemsSourceChanged(oldValue, newValue);
    340         //    this.InitDataSourceToComboBoxNodeList();
    341 
    342         //    DisplayText = null;
    343         //    OnApplyTemplate();
    344         //}
    345 
    346         protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    347         {
    348             base.OnItemsChanged(e);
    349             this.InitDataSourceToComboBoxNodeList();
    350 
    351             OnApplyTemplate();
    352         }
    353 
    354         public override void OnApplyTemplate()
    355         {
    356             base.OnApplyTemplate();
    357 
    358             if (this.MyListBox == null)
    359             {
    360                 return;
    361             }
    362 
    363             if (this.NodeList == null)
    364             {
    365                 return;
    366             }
    367 
    368             if (this.EditableTextBox != null)
    369             {
    370                 this.EditableTextBox.PreviewKeyUp += EditableTextBox_PreviewKeyUp;
    371                 this.EditableTextBox.TextChanged += new TextChangedEventHandler(EditableTextBox_TextChanged);
    372                 this.EditableTextBox.GotFocus += EditableTextBox_GotFocus;
    373                 this.EditableTextBox.MouseLeftButtonUp += EditableTextBox_MouseLeftButtonUp;
    374             }
    375         }
    376 
    377         void EditableTextBox_PreviewKeyUp(object sender, KeyEventArgs e)
    378         {
    379             TextBox text = sender as TextBox;
    380             this.FilterDataSourceByInputText(text.Text);
    381             if (!this.IsDropDownOpen)
    382                 this.IsDropDownOpen = true;
    383         }
    384 
    385         void EditableTextBox_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    386         {
    387             this.DisplayText = null;
    388             this.IsDropDownOpen = true;
    389         }
    390 
    391         private void EditableTextBox_GotFocus(object sender, RoutedEventArgs e)
    392         {
    393             this.DisplayText = null;
    394             this.IsDropDownOpen = true;
    395         }
    396 
    397         private void EditableTextBox_TextChanged(object sender, TextChangedEventArgs e)
    398         {
    399             TextBox text = sender as TextBox;
    400             this.FilterDataSourceByInputText(text.Text);
    401         }
    402 
    403         private void ToggleButtonClickCommandProcess()
    404         {
    405             this.DisplayText = null;
    406             this.IsDropDownOpen = true;
    407         }
    408 
    409         private void CheckBoxClickCommandProcess(ComboBoxNode node)
    410         {
    411             if (this.SelectedItems == null)
    412             {
    413                 return;
    414             }
    415 
    416             if (node.Title == SelectAllItem)
    417             {
    418                 foreach (var item in this.dataSourceNodeList)
    419                 {
    420                     if (item.IsEnabled)
    421                         item.IsSelected = node.IsSelected;
    422                 }
    423             }
    424             else
    425             {
    426                 var selectAllItem = this.dataSourceNodeList.Find(p => p.Title == SelectAllItem);
    427                 if (selectAllItem != null)
    428                 {
    429                     int count = this.dataSourceNodeList.Count(P => P.IsSelected && P.Title != SelectAllItem);
    430                     if (!node.IsSelected)
    431                     {
    432                         selectAllItem.IsSelected = false;
    433                     }
    434                     else if (count == this.dataSourceNodeList.Count - 1)
    435                     {
    436                         selectAllItem.IsSelected = true;
    437                     }
    438                 }
    439             }
    440 
    441         }
    442 
    443 
    444         #endregion
    445 
    446         #region Method
    447 
    448         /// <summary>
    449         /// Used to display selected item titles when popup closed
    450         /// </summary>
    451         /// <returns></returns>
    452         private string GetSelectedText()
    453         {
    454             StringBuilder sb = new StringBuilder();
    455             foreach (var item in this.dataSourceNodeList)
    456             {
    457                 if (!item.IsSelected)
    458                     continue;
    459                 if (item.Title == SelectAllItem)
    460                     continue;
    461 
    462                 sb.Append(item.Title).Append(SeparateString);
    463             }
    464 
    465             if (sb.Length > 0)
    466                 return sb.ToString().TrimEnd(SeparateString.ToCharArray());
    467             else
    468                 return null;
    469         }
    470 
    471         /// <summary>
    472         /// Use to generate new display items when search in text box
    473         /// </summary>
    474         /// <param name="inputText"></param>
    475         private void FilterDataSourceByInputText(string inputText)
    476         {
    477             this.NodeList.Clear();
    478             ObservableCollection<ComboBoxNode> tempSource = new ObservableCollection<ComboBoxNode>();
    479             if (!string.IsNullOrEmpty(inputText))
    480             {
    481                 this.NodeList = this.dataSourceNodeList.FindAll(
    482                     p => p.Title.StartsWith(inputText.Trim(), true, CultureInfo.CurrentCulture)).ToObservableCollection();
    483             }
    484             else
    485             {
    486                 this.NodeList = this.dataSourceNodeList.ToObservableCollection();
    487             }
    488         }
    489 
    490         private void InitDataSourceToComboBoxNodeList()
    491         {
    492             dataSourceNodeList.Clear();
    493             NodeList.Clear();
    494             TotalCount = 0;
    495             if (this.ItemsSource != null)
    496             {
    497                 ComboBoxNode selectAllNode = new ComboBoxNode(SelectAllItem);
    498                 dataSourceNodeList.Add(selectAllNode);
    499             }
    500 
    501             foreach (var item in this.ItemsSource)
    502             {
    503                 string title = item.GetType().GetProperty(this.DisplayMemberPath).GetValue(item, null).ToString();
    504                 bool isEnabled = true;
    505                 if (!string.IsNullOrWhiteSpace(this.ItemEnabledPath))
    506                 {
    507                     try
    508                     {
    509                         isEnabled = (bool)item.GetType().GetProperty(this.ItemEnabledPath).GetValue(item, null);
    510                     }
    511                     catch { }
    512                 }
    513                 ComboBoxNode node = new ComboBoxNode(title, item);
    514                 node.IsEnabled = isEnabled;
    515                 ChangeNodeIsSelectedStatus(node);
    516                 dataSourceNodeList.Add(node);
    517                 NodeList = dataSourceNodeList.ToObservableCollection();
    518             }
    519             //set total count when itemsource changed
    520             TotalCount = dataSourceNodeList.Count;
    521         }
    522 
    523 
    524         private void ChangeNodeIsSelectedStatus()
    525         {
    526             if (this.dataSourceNodeList != null && this.SelectedItems != null)
    527             {
    528                 int selectedCount = this.SelectedItems.Count;
    529                 foreach (var node in this.dataSourceNodeList)
    530                 {
    531                     ChangeNodeIsSelectedStatus(node);
    532                 }
    533             }
    534 
    535             this.DisplayText = GetSelectedText();
    536         }
    537 
    538         private void ChangeNodeIsSelectedStatus(ComboBoxNode node)
    539         {
    540             if (node != null && this.SelectedItems != null)
    541             {
    542                 int selectedCount = this.SelectedItems.Count;
    543                 if (node.Title == SelectAllItem)
    544                 {
    545                     if (selectedCount == TotalCount - 1)
    546                         node.IsSelected = true;
    547                     else
    548                         node.IsSelected = false;
    549                     return;
    550                 }
    551                 if (this.SelectedItems.Contains(node.Item))
    552                     node.IsSelected = true;
    553                 else
    554                     node.IsSelected = false;
    555             }
    556         }
    557 
    558 
    559 
    560         #endregion
    561     }
    562 }
    View Code
      1 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      2                     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      3                     xmlns:local="clr-namespace:Common.Controls.CustomControls"
      4                     xmlns:Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" 
      5                      xmlns:Attach="clr-namespace:Common.Common"
      6                     >
      7 
      8     <Style x:Key="MultiComboBoxEditableTextBox" TargetType="{x:Type TextBox}">
      9         <Setter Property="OverridesDefaultStyle" Value="true"/>
     10         <Setter Property="AllowDrop" Value="true"/>
     11         <Setter Property="MinWidth" Value="0"/>
     12         <Setter Property="MinHeight" Value="0"/>
     13         <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
     14         <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
     15         <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
     16         <Setter Property="Template">
     17             <Setter.Value>
     18                 <ControlTemplate TargetType="{x:Type TextBox}">
     19                     <ScrollViewer x:Name="PART_ContentHost" Background="Transparent" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
     20                 </ControlTemplate>
     21             </Setter.Value>
     22         </Setter>
     23     </Style>
     24     <Style  TargetType="{x:Type local:CustomMultipleDropDownBox}">
     25         <Setter Property="FocusVisualStyle">
     26             <Setter.Value>
     27                 <Style>
     28                     <Setter Property="Control.Template">
     29                         <Setter.Value>
     30                             <ControlTemplate>
     31                                 <Rectangle Margin="4,4,21,4" SnapsToDevicePixels="True" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
     32                             </ControlTemplate>
     33                         </Setter.Value>
     34                     </Setter>
     35                 </Style>
     36             </Setter.Value>
     37         </Setter>
     38         <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"/>
     39         <Setter Property="Background" Value="#ffffff"/>
     40         <Setter Property="Height" Value="28"></Setter>
     41         <Setter Property="Margin" Value="0"/>
     42         <Setter Property="Padding" Value="5,2,5,2"></Setter>
     43         <Setter Property="Foreground" Value="#0c223a"/>
     44         <Setter Property="FontFamily" Value="Arial" />
     45         <Setter Property="BorderThickness" Value="2"/>
     46         <Setter Property="VerticalContentAlignment" Value="Center" />
     47         <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
     48         <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
     49         <Setter Property="ScrollViewer.CanContentScroll" Value="True"/>
     50         <Setter Property="ScrollViewer.PanningMode" Value="Both"/>
     51         <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
     52         <Setter Property="Template">
     53             <Setter.Value>
     54                 <ControlTemplate TargetType="{x:Type local:CustomMultipleDropDownBox}">
     55                     <Border x:Name="BD" CornerRadius="5"  Background="{TemplateBinding Background}" BorderBrush="#5d7fad" BorderThickness="1" SnapsToDevicePixels="True" >
     56                         <Grid x:Name="MainGrid" SnapsToDevicePixels="True" >
     57                             <Grid.ColumnDefinitions>
     58                                 <ColumnDefinition Width="*" />
     59                                 <ColumnDefinition  Width="20"/>
     60                             </Grid.ColumnDefinitions>
     61                             <Popup x:Name="PART_Popup"  AllowsTransparency="True" Grid.ColumnSpan="2" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}"   PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
     62                                 <Themes:SystemDropShadowChrome  x:Name="Shdw"  Color="Transparent" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding ActualWidth, ElementName=Placement}" >
     63                                     <Border x:Name="DropDownBorder" Background="#FFFFFF" BorderThickness="1" CornerRadius="5" BorderBrush="#5d7fad" >
     64                                         <!--<StackPanel Orientation="Vertical">-->
     65                                         <!--<ListBox  x:Name="MyListBox"  Height="{TemplateBinding DropDownHeight}" Width="{TemplateBinding Width}"    SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
     66                                              KeyboardNavigation.DirectionalNavigation="Contained"   >
     67                                                 </ListBox>-->
     68                                         <ListBox  x:Name="MyListBox" Margin="2"   Width="{Binding Width,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}" 
     69                                                       ItemsSource="{Binding NodeList,Mode=OneWay,RelativeSource={RelativeSource TemplatedParent},UpdateSourceTrigger=PropertyChanged}"    
     70                                                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
     71                                              KeyboardNavigation.DirectionalNavigation="Contained"   Style="{DynamicResource MultiComboBoxListBox}">
     72 
     73                                         </ListBox>
     74                                         <!--<ListBox  Foreground="#0c223a" FontSize="14" FontFamily="Arial"  Height="{TemplateBinding DropDownHeight}" x:Name="MySelectedListBox"  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
     75                                              KeyboardNavigation.DirectionalNavigation="Contained" DisplayMemberPath="{TemplateBinding DisplayMemberPath}" ItemsSource="{TemplateBinding SelectedItems}" >
     76                                                 </ListBox>-->
     77                                         <!--</StackPanel>-->
     78                                     </Border>
     79                                 </Themes:SystemDropShadowChrome>
     80                             </Popup>
     81                             <ToggleButton  IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Grid.Column="1"  
     82                                            Name="ToggleButton" Focusable="True" Command="{Binding ToggleButtonClickCommand, RelativeSource={RelativeSource TemplatedParent}}"  ClickMode="Press" SnapsToDevicePixels="True" Style="{DynamicResource ComboBoxToggleButton2}"/>
     83                             <TextBox x:Name="DisPlayTextBlock" Padding="2"  BorderBrush="Red"  Text="{TemplateBinding DisplayText}"  VerticalAlignment="Center"    Background="Transparent"  Foreground="{TemplateBinding Foreground}" 
     84                                      FontSize="{TemplateBinding Foreground}" FontFamily="{TemplateBinding FontFamily}" HorizontalAlignment="Stretch" Style="{StaticResource MultiComboBoxEditableTextBox}">
     85                             </TextBox>
     86 
     87 
     88                         </Grid>
     89                     </Border>
     90                     <ControlTemplate.Triggers>
     91                         <!--<Trigger Property="Validation.HasError" Value="True">
     92                             <Setter TargetName="BD" Property="BorderBrush" Value="Red"></Setter>
     93                         </Trigger>-->
     94                         <Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="True">
     95                             <Setter Property="Margin" TargetName="Shdw" Value="0,0,5,5"/>
     96                             <Setter Property="Color" TargetName="Shdw" Value="#71000000"/>
     97                         </Trigger>
     98                         <Trigger Property="HasItems" Value="False">
     99                             <Setter Property="Height" TargetName="DropDownBorder" Value="95"/>
    100                         </Trigger>
    101                         <Trigger Property="IsEnabled" Value="False">
    102                             <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
    103                             <Setter Property="Background" Value="#FFF4F4F4"/>
    104                         </Trigger>
    105                         <MultiTrigger>
    106                             <MultiTrigger.Conditions>
    107                                 <Condition Property="IsGrouping" Value="True"/>
    108                                 <Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="False"/>
    109                             </MultiTrigger.Conditions>
    110                             <Setter Property="ScrollViewer.CanContentScroll" Value="False"/>
    111                         </MultiTrigger>
    112                         <!--<Trigger Property="CanContentScroll" SourceName="DropDownScrollViewer" Value="False">
    113                             <Setter Property="Canvas.Top" TargetName="OpaqueRect" Value="{Binding VerticalOffset, ElementName=DropDownScrollViewer}"/>
    114                             <Setter Property="Canvas.Left" TargetName="OpaqueRect" Value="{Binding HorizontalOffset, ElementName=DropDownScrollViewer}"/>
    115                         </Trigger>-->
    116                         <Trigger Property="Validation.HasError" Value="True">
    117                             <Setter Property="ToolTip">
    118                                 <Setter.Value>
    119                                     <Binding 
    120                             Path="(Validation.Errors).CurrentItem.ErrorContent"
    121                             RelativeSource="{x:Static RelativeSource.Self}"
    122                             />
    123                                 </Setter.Value>
    124                             </Setter>
    125                         </Trigger>
    126                         <Trigger Property="DisplayTextToolTip" Value="True">
    127                             <Setter Property="ToolTip">
    128                                 <Setter.Value>
    129                                     <Binding 
    130                             Path="DisplayText"
    131                             RelativeSource="{x:Static RelativeSource.Self}"
    132                             />
    133                                 </Setter.Value>
    134                             </Setter>
    135                         </Trigger>
    136                     </ControlTemplate.Triggers>
    137                 </ControlTemplate>
    138             </Setter.Value>
    139         </Setter>
    140         <Setter Property="Validation.ErrorTemplate">
    141             <Setter.Value>
    142                 <ControlTemplate>
    143                     <AdornedElementPlaceholder>
    144                         <Border BorderBrush="Red" BorderThickness="1" CornerRadius="5" SnapsToDevicePixels="True" />
    145 
    146                     </AdornedElementPlaceholder>
    147                 </ControlTemplate>
    148             </Setter.Value>
    149         </Setter>
    150         <Style.Triggers>
    151             <Trigger Property="Attach:AttachProperty.IsMandatory" Value="True">
    152                 <Setter Property="Background" Value="LightYellow"/>
    153             </Trigger>
    154             <Trigger Property="IsFocused" Value="True" >
    155                 <Setter Property="Button.Effect">
    156                     <Setter.Value>
    157                         <DropShadowEffect ShadowDepth="0" BlurRadius="8" Color="#fe1C67C7"></DropShadowEffect>
    158                     </Setter.Value>
    159                 </Setter>
    160             </Trigger>
    161             <Trigger Property="IsMouseOver" Value="True">
    162                 <Setter Property="Button.Effect">
    163                     <Setter.Value>
    164                         <DropShadowEffect ShadowDepth="0" BlurRadius="8" Color="#Fe9DBADF"></DropShadowEffect>
    165                     </Setter.Value>
    166                 </Setter>
    167             </Trigger>
    168             <Trigger Property="IsEnabled" Value="False">
    169                 <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
    170                 <Setter Property="Background" Value="#FFF4F4F4"/>
    171             </Trigger>
    172         </Style.Triggers>
    173     </Style>
    174     <Geometry x:Key="DownArrowGeometry">M 0 0 L 3.5 4 L 7 0 Z</Geometry>
    175     <Style x:Key="ComboBoxToggleButton2" TargetType="{x:Type ToggleButton}">
    176         <Setter Property="OverridesDefaultStyle" Value="true"/>
    177         <Setter Property="IsTabStop" Value="false"/>
    178         <Setter Property="Focusable" Value="false"/>
    179         <Setter Property="ClickMode" Value="Press"/>
    180         <Setter Property="Cursor" Value="Hand"/>
    181         <Setter Property="Background" Value="Transparent"/>
    182         <Setter Property="Template">
    183             <Setter.Value>
    184                 <ControlTemplate TargetType="{x:Type ToggleButton}">
    185                     <Grid>
    186                         <Grid.ColumnDefinitions>
    187                             <ColumnDefinition />
    188                             <ColumnDefinition Width="20" />
    189                         </Grid.ColumnDefinitions>
    190                         <Border x:Name="Border" Grid.ColumnSpan="2"  Background="{TemplateBinding Background}"   SnapsToDevicePixels="True" />
    191                         <Grid Grid.Column="1" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Background="{TemplateBinding Background}">
    192                             <Path x:Name="Arrow" Data="{StaticResource DownArrowGeometry}" Fill="#5d7fad" HorizontalAlignment="Center" Margin="0,1,0,0" VerticalAlignment="Center"/>
    193                         </Grid>
    194                     </Grid>
    195 
    196                 </ControlTemplate>
    197             </Setter.Value>
    198         </Setter>
    199     </Style>
    200     <Style x:Key="MultiComboBoxListBox" TargetType="{x:Type ListBox}">
    201         <Setter Property="BorderThickness" Value="0"></Setter>
    202         <Setter Property="ItemTemplate">
    203             <Setter.Value>
    204                 <DataTemplate>
    205                     <CheckBox Margin="0,2,0,0" IsChecked="{Binding IsSelected,Mode=TwoWay}"
    206                               IsEnabled="{Binding IsEnabled, Mode=OneWay}" 
    207                               Command="{Binding CheckBoxSelectCommand,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:CustomMultipleDropDownBox}}}"
    208                               CommandParameter="{Binding}"
    209                               Tag="{Binding Mode=OneWay,UpdateSourceTrigger=PropertyChanged}"
    210                               Content="{Binding Title}" 
    211                               Width="{Binding DropDownWidth,Mode=OneWay}"></CheckBox>
    212 
    213                 </DataTemplate>
    214             </Setter.Value>
    215         </Setter>
    216     </Style>
    217 </ResourceDictionary>
    View Code
  • 相关阅读:
    yum源的制作
    债券到期收益率计算公式
    IMP同库Type对象导入报错ORA-02304
    oracle自动挂掉问题分析
    CPP读取dbf文件
    oracle忘记system密码
    沪C转浙A
    业务词汇
    VS2017使用Resharp开发CPP程序
    CPP调用webservice
  • 原文地址:https://www.cnblogs.com/vincentsun1234/p/3487649.html
Copyright © 2020-2023  润新知