1. 程式人生 > >【轉】WPF自定義控制元件與樣式(8)-ComboBox與自定義多選控制元件MultComboBox

【轉】WPF自定義控制元件與樣式(8)-ComboBox與自定義多選控制元件MultComboBox

一.前言

  申明:WPF自定義控制元件與樣式是一個系列文章,前後是有些關聯的,但大多是按照由簡到繁的順序逐步釋出的等。

  本文主要內容:

  • 下拉選擇控制元件ComboBox的自定義樣式及擴充套件;
  • 自定義多選控制元件MultiComboBox;

二.下拉選擇控制元件ComboBox的自定義樣式及擴充套件

2.1基本樣式

  先看看基礎效果圖:

 

  從功能上ComboBox有兩種狀態:

    • 可編輯文字;
    • 不可編輯文字。

從XAML的邏輯樹結構上看,分為幾個部分:

    • 顯示當前內容的區域;
    • 下拉按鈕,一般使用ToggleButton;
    • 彈出的下拉選項列表,使用Popup作為容器;

樣式定義程式碼:  

<!--下拉條目樣式-->
    <Style TargetType="ComboBoxItem" x:Key="ComboBoxItemStyle">
        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
        <Setter Property="VerticalContentAlignment" Value="Center" />
        <Setter Property="RenderOptions.ClearTypeHint" Value="Enabled" />
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="Height" Value="28" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ComboBoxItem">
                    <Grid Background="
{TemplateBinding Background}" Margin="0,0.5"> <Border x:Name="ItemBackground" IsHitTestVisible="False" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush
}" Background="{TemplateBinding Background}" /> <ContentPresenter x:Name="contentPresenter" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" /> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter TargetName="ItemBackground" Property="Background" Value="{StaticResource ItemSelectedBackground}" /> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="ItemBackground" Property="Background" Value="{StaticResource ItemMouseOverBackground}" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <!--水印:local:ControlAttachProperty.Watermark--> <!--Label區域:local:ControlAttachProperty.LabelTemplate ,local:ControlAttachProperty.Label--> <!--附加內容區域:local:ControlAttachProperty.AttachContent--> <!--圓角:local:ControlAttachProperty.CornerRadius--> <!--local:ControlAttachProperty.MouseOverBorderBrush--> <!--local:ControlAttachProperty.FocusBorderBrush--> <!--local:ControlAttachProperty.FocusBackground--> <Style TargetType="{x:Type ComboBox}" x:Key="DefaultComboBox"> <Setter Property="Height" Value="30" /> <Setter Property="Width" Value="200" /> <Setter Property="Foreground" Value="{StaticResource TextForeground}" /> <Setter Property="Background" Value="{StaticResource TextBackground}" /> <Setter Property="HorizontalContentAlignment" Value="Stretch" /> <Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="BorderThickness" Value="1" /> <Setter Property="BorderBrush" Value="{StaticResource ControlBorderBrush}" /> <Setter Property="local:ControlAttachProperty.FocusBackground" Value="{StaticResource FocusBackground}" /> <Setter Property="local:ControlAttachProperty.FocusBorderBrush" Value="{StaticResource FocusBorderBrush}" /> <Setter Property="local:ControlAttachProperty.MouseOverBorderBrush" Value="{StaticResource MouseOverBorderBrush}" /> <Setter Property="FontFamily" Value="{StaticResource FontFamily}" /> <Setter Property="FontSize" Value="{StaticResource FontSize}" /> <Setter Property="ItemContainerStyle" Value="{StaticResource ComboBoxItemStyle}" /> <Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="MaxDropDownHeight" Value="400" /> <Setter Property="ScrollViewer.CanContentScroll" Value="False" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ComboBox}"> <Grid x:Name="PART_Root"> <Border x:Name="Bg" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" CornerRadius="{TemplateBinding local:ControlAttachProperty.CornerRadius}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" /> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="21" /> </Grid.ColumnDefinitions> <!--Label區域--> <ContentControl x:Name="Label" Template="{TemplateBinding local:ControlAttachProperty.LabelTemplate}" IsTabStop="False" IsHitTestVisible="False" Content="{TemplateBinding local:ControlAttachProperty.Label}" Margin="1,1,0,1"/> <!--附加內容區域--> <Border x:Name="PART_AttachContent" Panel.ZIndex="2" Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Center" > <ContentControl VerticalAlignment="Center" VerticalContentAlignment="Center" Template="{TemplateBinding local:ControlAttachProperty.AttachContent}" /> </Border> <!--下拉按鈕--> <ToggleButton x:Name="PART_DropDownToggle" IsTabStop="False" Style="{StaticResource ComboToggleButton}" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Grid.Column="1" Grid.ColumnSpan="3" IsEnabled="{Binding Path=IsReadOnly,RelativeSource={RelativeSource TemplatedParent}, Converter={x:Static local:XConverter.TrueToFalseConverter},Mode=OneWay}" Background="{TemplateBinding local:ControlAttachProperty.FocusBackground}"/> <!--水印--> <Border Grid.Column="1"> <TextBlock x:Name="Message" Padding="0" Visibility="Collapsed" Text="{TemplateBinding local:ControlAttachProperty.Watermark}" Foreground="{TemplateBinding Foreground}" IsHitTestVisible="False" Opacity="{StaticResource WatermarkOpacity}" HorizontalAlignment="Left" TextAlignment="Center" VerticalAlignment="Center" Margin="5,2,5,2" /> </Border> <!--主內容區域--> <Grid Grid.Column="1" x:Name="ContentSite" Margin="2 0 0 0" > <ContentPresenter x:Name="PART_SelectedItem" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" Content="{TemplateBinding SelectionBoxItem}" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" HorizontalAlignment="Stretch" Margin="2,0,2,0" IsHitTestVisible="False" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" /> <!--文字編輯--> <TextBox x:Name="PART_EditableTextBox" Style="{StaticResource EditableTextBoxStyle}" Visibility="Collapsed" HorizontalAlignment="Stretch" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" IsHitTestVisible="True" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" IsReadOnly="{TemplateBinding IsReadOnly}" FontFamily="{TemplateBinding FontFamily}" Foreground="{TemplateBinding Foreground}" Text="{TemplateBinding Text}" FontSize="{TemplateBinding FontSize}" /> </Grid> </Grid> <!--彈出下拉控制元件--> <Popup x:Name="PART_Popup" AllowsTransparency="True" Focusable="False" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom"> <Grid Width="{Binding ActualWidth, RelativeSource={RelativeSource TemplatedParent}}" MaxHeight="{Binding MaxDropDownHeight, RelativeSource={RelativeSource TemplatedParent}}"> <Border x:Name="PopupBorder" BorderThickness="{TemplateBinding BorderThickness}" HorizontalAlignment="Stretch" Height="Auto" BorderBrush="{TemplateBinding BorderBrush}" Background="{StaticResource PopupBackground}"> </Border> <ScrollViewer x:Name="DropDownScrollViewer" BorderThickness="0" Margin="1"> <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" /> </ScrollViewer> </Grid> </Popup> </Grid> <!--觸發器--> <ControlTemplate.Triggers> <!--1.顯示水印--> <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value=""> <Setter TargetName="Message" Property="Visibility" Value="Visible" /> </DataTrigger> <!--編輯模式--> <Trigger Property="IsEditable" Value="True"> <Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible" /> <Setter TargetName="PART_SelectedItem" Property="Visibility" Value="Collapsed" /> <Setter TargetName="PART_DropDownToggle" Property="Grid.Column" Value="3" /> <Setter TargetName="PART_DropDownToggle" Property="Grid.ColumnSpan" Value="1" /> <Setter TargetName="PART_DropDownToggle" Property="Background" Value="Transparent" /> <Setter Property="IsTabStop" Value="false" /> <Setter TargetName="PART_DropDownToggle" Property="Focusable" Value="False" /> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.MouseOverBorderBrush),RelativeSource={RelativeSource Self}}"/> </Trigger> <Trigger Property="IsFocused" Value="True"> <Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.FocusBorderBrush),RelativeSource={RelativeSource Self}}"/> </Trigger> <Trigger Property="IsKeyboardFocusWithin" Value="True"> <Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.FocusBorderBrush),RelativeSource={RelativeSource Self}}"/> </Trigger> <Trigger Property="IsEnabled" Value="False"> <Setter TargetName="PART_Root" Property="Opacity" Value="{StaticResource DisableOpacity}"></Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>

如果看過本系列前面的文章,對上面的程式碼就更容易理解了,為了方便支援水印、Label標籤、清除內容功能擴充套件,在基礎樣式里加了額外的部分,在xaml中有註釋說明。 

2.2 Label標籤樣式

效果圖:

在2.1的基礎樣式上擴充套件即可:  

<!--ComboBox包含附加屬性Label的樣式 LabelComboBox -->
    <Style TargetType="{x:Type ComboBox}" x:Key="LabelComboBox" BasedOn="{StaticResource DefaultComboBox}">
        <Setter Property="Width" Value="260"></Setter>
        <Setter Property="local:ControlAttachProperty.LabelTemplate" >
            <Setter.Value>
                <ControlTemplate TargetType="ContentControl">
                    <Border Width="60" Background="{StaticResource TextLabelBackground}">
                        <TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="2" Text="{TemplateBinding Content}"></TextBlock>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

使用示例:  

<ComboBox Margin="5" ItemsSource="{StaticResource items}" core:ControlAttachProperty.Label="選擇性別" 
                      Style="{StaticResource LabelComboBox}"  core:ControlAttachProperty.Watermark="水印" />
            <ComboBox Margin="5" IsEditable="True" ItemsSource="{StaticResource items}" core:ControlAttachProperty.Label="選擇性別" 
                      Style="{StaticResource LabelComboBox}" core:ControlAttachProperty.Watermark="我收水3333333333333333333333印" />
            <ComboBox Margin="5" IsEnabled="False" ItemsSource="{StaticResource items}" core:ControlAttachProperty.Label="選擇性別" 
                      Style="{StaticResource LabelComboBox}" SelectedIndex="3" />

2.3 擴充套件清除選中項/文字按鈕樣式

效果圖:

同樣,也是在2.1的基礎樣式上擴充套件:  

<!--ComboBox包含清除Text按鈕的樣式 ClearButtonComboBox -->
    <Style TargetType="{x:Type ComboBox}" x:Key="ClearButtonComboBox" BasedOn="{StaticResource DefaultComboBox}">
        <Setter Property="local:ControlAttachProperty.AttachContent">
            <Setter.Value>
                <ControlTemplate>
                    <local:FButton FIcon="&#xe60a;" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"
                                   local:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.ClearTextCommand" 
                                   CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ComboBox}}}"
                                   IsEnabled="{Binding Path=IsReadOnly,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ComboBox}},
                        Converter={x:Static local:XConverter.TrueToFalseConverter},Mode=OneWay}"
                               Margin="1,3,0,4" FIconSize="14" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <!--ComboBox包含附加屬性Label,以及ClearText按鈕的樣式 LabelClearButtonComboBox -->
    <Style TargetType="{x:Type ComboBox}" x:Key="LabelClearButtonComboBox" BasedOn="{StaticResource DefaultComboBox}">
        <Setter Property="Width" Value="280"></Setter>
        <Setter Property="local:ControlAttachProperty.LabelTemplate" >
            <Setter.Value>
                <ControlTemplate TargetType="ContentControl">
                    <Border Width="60" Background="{StaticResource TextLabelBackground}">
                        <TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="2" Text="{TemplateBinding Content}"></TextBlock>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="local:ControlAttachProperty.AttachContent">
            <Setter.Value>
                <ControlTemplate>
                    <local:FButton FIcon="&#xe60a;" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"
                               local:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.ClearTextCommand" 
                               CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ComboBox}}}"
                                   IsEnabled="{Binding Path=IsReadOnly,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ComboBox}},
                        Converter={x:Static local:XConverter.TrueToFalseConverter},Mode=OneWay}"
                               Margin="0,3,0,4" FIconSize="14" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

使用示例:

 <ComboBox Margin="5" IsEnabled="False" ItemsSource="{StaticResource items}" core:ControlAttachProperty.Label="選擇性別" 
                      Style="{StaticResource LabelClearButtonComboBox}" SelectedIndex="3" />
            <ComboBox Margin="5" ItemsSource="{StaticResource items}" core:ControlAttachProperty.Label="選擇性別"
                      Style="{StaticResource ClearButtonComboBox}"  core:ControlAttachProperty.Watermark="水印" />

三.自定義多選控制元件MultiComboBox

  實際需求中,經常有多選的要求,基於ComboBox簡單的實現了一個多選控制元件MultiComboBox。效果圖:

  在功能上,可以滿足基本需求,實際功能還不完整的,可以根據自己的需求完善,後臺C#程式碼:

/// <summary>
    /// MultiComboBox.xaml 的互動邏輯
    /// </summary>
    [TemplatePart(Name = "PART_ListBox", Type = typeof(ListBox))]
    public partial class MultiComboBox : ComboBox
    {
        /// <summary>
        /// 獲取選擇項集合
        /// </summary>
        public IList SelectedItems
        {
            get { return this._ListBox.SelectedItems; }
        }

        /// <summary>
        /// 設定或獲取選擇項
        /// </summary>
        public new int SelectedIndex
        {
            get { return this._ListBox.SelectedIndex; }
            set { this._ListBox.SelectedIndex = value; }
        }

        private ListBox _ListBox;

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this._ListBox = Template.FindName("PART_ListBox", this) as ListBox;
            this._ListBox.SelectionChanged += _ListBox_SelectionChanged;
        }

        void _ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var item in this.SelectedItems)
            {
                sb.Append(item.ToString()).Append(";");
            }
            this.Text = sb.ToString().TrimEnd(';');
        }


        static MultiComboBox()
        {
            //OverridesDefaultStyleProperty.OverrideMetadata(typeof(MultiComboBox), new FrameworkPropertyMetadata(typeof(MultiComboBox)));
        }

        public MultiComboBox()
        {
            ListBox ls = new ListBox();
            //ls.SelectedItems
        }

        public void SelectAll()
        {
            this._ListBox.SelectAll();

        }

        public void UnselectAll()
        {
            this._ListBox.UnselectAll();
        }
    }

樣式上,也實現了同第二節一樣的擴充套件,包括支援水印、Label標籤、清除內容功能擴充套件,就不做具體介紹了,基礎樣式程式碼:

<!--多選項樣式-->
    <Style x:Key="CheckItemStyle" TargetType="{x:Type ListBoxItem}" >
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListBoxItem}" >
                    <Border x:Name="Border" Background="{TemplateBinding Background}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
                        <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                            <CheckBox IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}">
                                <ContentPresenter Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                            </CheckBox>
                        </StackPanel>
                    </Border>
                    <ControlTemplate.Triggers>
                        <!--<Trigger Property="IsSelected" Value="True">
                            <Setter TargetName="Border" Property="Background" Value="{StaticResource ItemSelectedBackground}" />
                            <Setter Property="Foreground" Value="{StaticResource ItemSelectedForeground}" />
                        </Trigger>-->
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="Border" Property="Background" Value="{StaticResource ItemMouseOverBackground}" />
                            <Setter Property="Foreground" Value="{StaticResource ItemMouseOverForeground}" />
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter TargetName="Border" Property="Opacity" Value="{StaticResource DisableOpacity}" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!--MultiComboBox普通樣式-->
    <Style x:Key="DefaultMultiComboBox" TargetType="{x:Type local:MultiComboBox}">
        <Setter Property="Height" Value="30" />
        <Setter Property="Width" Value="200" />
        <Setter Property="Foreground" Value="{StaticResource TextForeground}" />
        <Setter Property="Background" Value="{StaticResource TextBackground}" />
        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
        <Setter Property="VerticalContentAlignment" Value="Center" />
        <Setter Property="BorderThickness" Value="1" />
        <Setter Property="BorderBrush" Value="{StaticResource ControlBorderBrush}" />
        <Setter Property="local:ControlAttachProperty.FocusBackground" Value="{StaticResource FocusBackground}" />
        <Setter Property="local:ControlAttachProperty.FocusBorderBrush" Value="{StaticResource FocusBorderBrush}" />
        <Setter Property="local:ControlAttachProperty.MouseOverBorderBrush" Value="{StaticResource MouseOverBorderBrush}" />
        <Setter Property="FontFamily" Value="{StaticResource FontFamily}" />
        <Setter Property="FontSize" Value="{StaticResource FontSize}" />
        <Setter Property="SnapsToDevicePixels" Value="True" />
        <Setter Property="MaxDropDownHeight" Value="400" />
        <Setter Property="ScrollViewer.CanContentScroll" Value="False" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:MultiComboBox}">
                    <Grid x:Name="PART_Root">
                        <Border x:Name="Bg" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
                                Background="{TemplateBinding Background}" />
                        <Grid x:Name="PART_InnerGrid" Margin="0">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="*" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="21" />
                            </Grid.ColumnDefinitions>
                            <!--Label區域-->
                            <ContentControl x:Name="Label" Template="{TemplateBinding local:ControlAttachProperty.LabelTemplate}" IsTabStop="False" IsHitTestVisible="False"
                                            Content="{TemplateBinding local:ControlAttachProperty.Label}" Margin="1,1,0,1"/>
                            <!--附加內容區域-->
                            <Border x:Name="PART_AttachContent" Panel.ZIndex="2" Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Center" >
                                <ContentControl VerticalAlignment="Center" VerticalContentAlignment="Center" Template="{TemplateBinding local:ControlAttachProperty.AttachContent}" />
                            </Border>
                            <!--下拉按鈕-->
                            <ToggleButton x:Name="PART_DropDownToggle" Panel.ZIndex="1" IsTabStop="False" Style="{StaticResource ComboToggleButton}" 
                                         IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
                                         Grid.Column="1"  Grid.ColumnSpan="3" IsEnabled="{Binding Path=IsReadOnly,RelativeSource={RelativeSource TemplatedParent},
                                            Converter={x:Static local:XConverter.TrueToFalseConverter},Mode=OneWay}"
                                          Background="{TemplateBinding local:ControlAttachProperty.FocusBackground}"/>
                            <!--水印-->
                            <Border Grid.Column="1">
                                <TextBlock x:Name="Message"  Padding="0" Visibility="Collapsed" Text="{TemplateBinding local:ControlAttachProperty.Watermark}" 
                                       Foreground="{TemplateBinding Foreground}" IsHitTestVisible="False" Opacity="0.6" HorizontalAlignment="Left" TextAlignment="Center" 
                                       VerticalAlignment="Center" Margin="5,2,5,2" />
                            </Border>
                            <!--內容區-->
                            <Grid Grid.Column="1"  Margin="2 0 0 0">
                                <!--文字編輯-->
                                <TextBox  x:Name="PART_EditableTextBox" Style="{StaticResource EditableTextBoxStyle}" FontSize="{TemplateBinding FontSize}"
                                         HorizontalAlignment="Stretch" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" IsHitTestVisible="True"
                                         HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                         IsReadOnly="{TemplateBinding IsReadOnly}" FontFamily="{TemplateBinding FontFamily}" Foreground="{TemplateBinding Foreground}"
                                         Text="{Binding Path=Text,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"  />
                            </Grid>
                            <!--彈出多選列表-->
                            <Popup x:Name="PART_Popup" AllowsTransparency="True" Focusable="False" StaysOpen="False"
                               IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}"
                               PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
                                <Grid Width="{Binding ActualWidth, RelativeSource={RelativeSource TemplatedParent}}" MaxHeight="{Binding MaxDropDownHeight, RelativeSource={RelativeSource TemplatedParent}}">
                                    <Border x:Name="PopupBorder" BorderThickness="{TemplateBinding BorderThickness}" HorizontalAlignment="Stretch"
                                        Height="Auto" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}"/>
                                    <ListBox x:Name="PART_ListBox" SelectionMode="Multiple" ItemsSource="{Binding ItemsSource,RelativeSource={RelativeSource TemplatedParent}}"
                                             ItemTemplate="{TemplateBinding ItemTemplate}"
                                             MaxHeight="{TemplateBinding MaxDropDownHeight}" ItemContainerStyle="{StaticResource CheckItemStyle}"/>
                                </Grid>
                            </Popup>
                        </Grid>
                    </Grid>
                    <!--觸發器-->
                    <ControlTemplate.Triggers>
                        <!--1.顯示水印-->
                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="">
                            <Setter TargetName="Message" Property="Visibility" Value="Visible" />
                        </DataTrigger>
                        <!--編輯模式-->
                        <Trigger Property="IsEditable" Value="True">
                            <Setter TargetName="PART_DropDownToggle" Property="Grid.Column" Value="3" />
                            <Setter TargetName="PART_DropDownToggle" Property="Grid.ColumnSpan" Value="1" />
                            <Setter TargetName="PART_DropDownToggle" Property="Background" Value="Transparent" />
                            <Setter Property="IsTabStop" Value="false" />
                            <Setter TargetName="PART_DropDownToggle" Property="Focusable" Value="False" />
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.MouseOverBorderBrush),RelativeSource={RelativeSource Self}}"/>
                        </Trigger>
                        <Trigger Property="IsFocused" Value="True">
                            <Setter  Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.FocusBorderBrush),RelativeSource={RelativeSource Self}}"/>
                        </Trigger>
                        <Trigger Property="IsKeyboardFocusWithin" Value="True">
                            <Setter  Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.FocusBorderBrush),RelativeSource={RelativeSource Self}}"/>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter TargetName="PART_Root" Property="Opacity" Value="{StaticResource DisableOpacity}"></Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!--MultiComboBox包含清除Text按鈕的樣式 ClearButtonMultiComboBox -->
    <Style TargetType="{x:Type local:MultiComboBox}" x:Key="ClearButtonMultiComboBox" BasedOn="{StaticResource DefaultMultiComboBox}">
        <Setter Property="local:ControlAttachProperty.AttachContent">
            <Setter.Value>
                <ControlTemplate>
                    <local:FButton FIcon="&#xe60a;" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"
                                   local:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.ClearTextCommand" 
                                   CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:MultiComboBox}}}"
                                   IsEnabled="{Binding Path=IsReadOnly,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:MultiComboBox}},
                        Converter={x:Static local:XConverter.TrueToFalseConverter},Mode=OneWay}"
                               Margin="1,3,0,4" FIconSize="14" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!--MultiComboBox包含附加屬性Label的樣式 LabelMultiComboBox -->
    <Style TargetType="{x:Type local:MultiComboBox}" x:Key="LabelMultiComboBox" BasedOn="{StaticResource DefaultMultiComboBox}">
        <Setter Property="Width" Value="260"></Setter>
        <Setter Property="local:ControlAttachProperty.LabelTemplate" >
            <Setter.Value>
                <ControlTemplate TargetType="ContentControl">
                    <Border Width="60" Background="{StaticResource TextLabelBackground}">
                        <TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="2" Text="{TemplateBinding Content}"></TextBlock>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!--MultiComboBox包含附加屬性Label,以及ClearText按鈕的樣式 LabelClearButtonMultiComboBox -->
    <Style TargetType="{x:Type local:MultiComboBox}" x:Key="LabelClearButtonMultiComboBox" BasedOn="{StaticResource DefaultMultiComboBox}">
        <Setter Property="Width" Value="280"></Setter>
        <Setter Property="local:ControlAttachProperty.LabelTemplate" >
            <Setter.Value>
                <ControlTemplate TargetType="ContentControl">
                    <Border Width="60" Background="{StaticResource TextLabelBackground}">
                        <TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="2" Text="{TemplateBinding Content}"></TextBlock>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="local:ControlAttachProperty.AttachContent">
            <Setter.Value>
                <ControlTemplate>
                    <local:FButton FIcon="&#xe60a;" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0"
                               local:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.ClearTextCommand" 
                               CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:MultiComboBox}}}"
                                   IsEnabled="{Binding Path=IsReadOnly,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:MultiComboBox}},
                        Converter={x:Static local:XConverter.TrueToFalseConverter},Mode=OneWay}"
                               Margin="0,3,0,4" FIconSize="14" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!--預設樣式-->
    <Style TargetType="{x:Type local:MultiComboBox}" BasedOn="{StaticResource DefaultMultiComboBox}"></Style>

使用例項:  

<core:MultiComboBox Width="420" Margin="3" IsEditable="True" ItemsSource="{StaticResource itmes}" 
                   core:ControlAttachProperty.Label="分類:" core:ControlAttachProperty.Watermark="...哈哈" Style="{StaticResource ClearButtonMultiComboBox}"/>
            <core:MultiComboBox Width="420" Margin="3" IsEditable="True" ItemsSource="{StaticResource itmes}"
                   core:ControlAttachProperty.Label="分類:" core:ControlAttachProperty.Watermark="...哈哈" Style="{StaticResource LabelMultiComboBox}"/>
            <core:MultiComboBox Width="420" Margin="3" IsEditable="False" ItemsSource="{StaticResource itmes}"
                   core:ControlAttachProperty.Label="分類:" core:ControlAttachProperty.Watermark="...哈哈" Style="{StaticResource LabelClearButtonMultiComboBox}"/>

            <core:MultiComboBox Width="420" Margin="3" IsEditable="True" ItemsSource="{StaticResource itmes}" IsReadOnly="True" SelectedIndex="3"
                   core:ControlAttachProperty.Label="分類:" core:ControlAttachProperty.Watermark="...哈哈" Style="{StaticResource LabelClearButtonMultiComboBox}"/>

            <core:MultiComboBox Width="420" Margin="3" IsEditable="False" ItemsSource="{StaticResource itmes}" IsEnabled="False"
                   core:ControlAttachProperty.Label="分類:" core:ControlAttachProperty.Watermark="...哈哈" Style="{StaticResource LabelClearButtonMultiComboBox}"/>

補充:EditableTextBoxStyle及ComboToggleButton樣式程式碼:

<Style TargetType="{x:Type ToggleButton}" x:Key="ComboToggleButton">
        <Setter Property="Foreground" Value="{StaticResource TextForeground}" />
        <Setter Property="local:ControlAttachProperty.FIconSize" Value="18"/>
        <Setter Property="local:ControlAttachProperty.FIconMargin" Value="0,1,3,1"/>
        <Setter Property="local:ControlAttachProperty.FIcon" Value="&#xe665;"/>
        <Setter Property="SnapsToDevicePixels" Value="True" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ToggleButton}">
                    <Grid x:Name="Grid">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="Auto"/>
                        </Grid.ColumnDefinitions>
                        <Border Background="{TemplateBinding Background}" x:Name="Bg" Grid.ColumnSpan="2" Margin="0,1,1,1"
                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"  Opacity="0.3"/>
                        <TextBlock Grid.Column="1" x:Name="FIcon" FontSize="{Binding Path=(local:ControlAttachProperty.FIconSize),RelativeSource={RelativeSource TemplatedParent}}"
                                   Text="{TemplateBinding local:ControlAttachProperty.FIcon}" 
                                   local:ControlAttachProperty.AllowsAnimation="{TemplateBinding IsChecked}"
                                   Foreground="{TemplateBinding Foreground}" Style="{StaticResource FIcon}"
                                   Margin="{TemplateBinding local:ControlAttachProperty.FIconMargin}"/>
                    </Grid>
                    <!--z觸發器-->
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="Foreground" Value="{StaticResource MouseOverForeground}" />
                            <Setter Property="Opacity" TargetName="Bg" Value="0.55" />
                        </Trigger>
                        <Trigger Property="IsPressed" Value="True">
                            <Setter Property="Foreground" Value="{StaticResource PressedForeground}" />
                            <Setter Property="Opacity" TargetName="Bg" Value="0.6" />
                        </Trigger>
                        <Trigger Property="IsChecked" Value="True">
                            <Setter Property="Foreground" Value="{StaticResource PressedForeground}" />
                            <Setter Property="Opacity" TargetName="Bg" Value="0.6" />
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Opacity" Value="{StaticResource DisableOpacity}" TargetName="Grid"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

   <!--編輯狀態文字框樣式-->
    <Style TargetType="{x:Type TextBox}" x:Key="EditableTextBoxStyle">
        <Setter Property="Margin" Value="1"/>
        <Setter Property="Padding" Value="0"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="Background" Value="{x:Null}"/>
        <Setter Property="MaxLength" Value="2048"/>
        <Setter Property="Foreground" Value="{StaticResource TextForeground}"/>
        <Setter Property="ContextMenu" Value="{DynamicResource TextBoxContextMenu}" />
        <Setter Property="SelectionBrush" Value="{StaticResource TextSelectionBrush}" />
        <Setter Property="FontSize" Value="{StaticResource FontSize}"></Setter>
        <Setter Property="FontFamily" Value="{StaticResource FontFamily}"></Setter>
        <Setter Property="Focusable" Value="True"/>
        <Setter Property="CaretBrush" Value="{StaticResource TextForeground}" />
        <Setter Property="VerticalAlignment" Value="Center" />
        <Setter Property="SnapsToDevicePixels" Value="True"></Setter>
        <Style.Triggers>
            <Trigger Property="IsReadOnly" Value="True">
                <Setter Property="Opacity" Value="{StaticResource ReadonlyOpacity}"></Setter>
            </Trigger>
            <Trigger Property="IsEnabled" Value="False">
                <Setter Property="Opacity" Value="{StaticResource DisableOpacity}"></Setter>
            </Trigger>
        </Style.Triggers>
    </Style>

 

原文地址:https://www.cnblogs.com/anding/p/4993655.html