wpf VS2017 带图片显示的自定义Combox

先看下效果图

 

 思路大概是将ComboxItem分为4列,然后将下拉框选中的值设置到Combox中

首先新建一个wpf的工程,取名为PictureCombox

1.添加需要用的png图,先导入图片两张,取名0.png和1.png(这个用画图板随便画都可以的,然后放到工程目录中,导入到工程里面)

2.添加一个绑定属性的类,文件为CbbData.cs,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PictureCombox
{
    class CbbData
    {
        public string data1 { get; set; }

        public string data2 { get; set; }

        public string dataAll { get; set; }

        public string ImgNameLeft { get; set; }

        public string ImgNameRight { get; set; }
    }
}
View Code

3.添加一个图片转换器类ImageConverter.cs文件,代码如下:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows.Media.Imaging;

namespace PictureCombox
{
    class ImageConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
                return null;
            string imgName = value.ToString();

            if (imgName == "")
                return null;

            BitmapImage bitmap = CreateBitmap.GetBitmap(imgName);
            return bitmap;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    class ImageLeftConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null )
                return null;

            string imgName = value.ToString();

            if (imgName == "")
                return null;

            string[] stringArray = imgName.Split(",".ToCharArray());

            stringArray[0] = (int.Parse(stringArray[0]) % 2).ToString();
            
            BitmapImage bitmap = CreateBitmap.GetBitmap(stringArray[0]);
            return bitmap;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    class ImageRightConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
                return null;

            string imgName = value.ToString();

            if (imgName == "")
                return null;

            string[] stringArray = imgName.Split(",".ToCharArray());

            if (stringArray.Length > 1)
            {
                stringArray[1] = (int.Parse(stringArray[1]) % 2).ToString();
                BitmapImage bitmap = CreateBitmap.GetBitmap(stringArray[1]);
                return bitmap;
            }
            else
            {
                stringArray[0] = (int.Parse(stringArray[0]) % 2).ToString();
                BitmapImage bitmap = CreateBitmap.GetBitmap(stringArray[0]);
                return bitmap;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    class ComboxLeftStringConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
                return null;

            string strAll = value.ToString();

            string[] stringArray = strAll.Split(",".ToCharArray());

            String stringTarget = String.Format("{0,-3}", stringArray[0]);

            return stringTarget;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    class ComboxRightStringConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
                return null;

            string strAll = value.ToString();

            string[] stringArray = strAll.Split(",".ToCharArray());

            String stringTarget;

            if (stringArray.Length > 1)
            {
                stringTarget = String.Format("{0,-3}", stringArray[1]);
            }
            else
            {
                stringTarget = String.Format("{0,-3}", stringArray[0]);
            }

            return stringTarget;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}
View Code

4.添加一个CreateBitmap.cs文件,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;

namespace PictureCombox
{
    class CreateBitmap
    {
        public static BitmapImage GetBitmap(string name)
        {
            BitmapImage bitmap;
            string rootPath = @"pack://application:,,,/" + name + ".png";
            bitmap = new BitmapImage(new Uri(rootPath, UriKind.Absolute));
            return bitmap;
        }
    }
}
View Code

5.最后再添加资源文件CustomDictionary.xaml,代码如下:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:PictureCombox">
    
    <local:ImageConverter x:Key="ImageConverter"/>
    <local:ImageLeftConverter x:Key="ImageLeftConverter"/>
    <local:ImageRightConverter x:Key="ImageRightConverter"/>
    
    <local:ComboxLeftStringConverter x:Key="ComboxLeftStringConverter"/>
    <local:ComboxRightStringConverter x:Key="ComboxRightStringConverter"/>
    
    <ControlTemplate x:Key="MyComboBoxItem"
                         TargetType="ComboBoxItem">
        <Grid Background="{TemplateBinding Background}"
                  >
            <Border x:Name="itemBorder"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        BorderBrush="Red"
                        Background="LightBlue"
                        Height="40"
                        >
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"></ColumnDefinition>
                        <ColumnDefinition Width="*"></ColumnDefinition>
                        <ColumnDefinition Width="*"></ColumnDefinition>
                        <ColumnDefinition Width="*"></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    
                    <Image Grid.Column="0" Margin="3" Source="{Binding ImgNameLeft,Converter={StaticResource ImageConverter}}"/>
                    <!--<Path Grid.Column="0" Stroke="Black" StrokeThickness="2" Margin="5" Data="M 0,0  L 0,25  L 25,25  L 25,0 Z"/>-->

                    <TextBlock Grid.Column="1" Text="{Binding data1}" 
                                   Margin="0,0,0,0"
                                   HorizontalAlignment="Left"
                                   VerticalAlignment="Center"
                                   TextAlignment="Center"/>
                    
                    <Image Grid.Column="2" Margin="4" Source="{Binding ImgNameRight,Converter={StaticResource ImageConverter}}"/>
                    <!--<Path Grid.Column="2" Stroke="Black" StrokeThickness="2" Margin="5" Data="M 12,12 A 10,10 0 1 1 12,11.9 Z"/>
                    <Path Grid.Column="2" Stroke="Black" StrokeThickness="2" Margin="0,0,0,0" Data="M 7,5 L 7,30"/>-->

                    <TextBlock Grid.Column="3" Text="{Binding data2}" 
                                   Margin="0,0,0,0"
                                   HorizontalAlignment="Left"
                                   VerticalAlignment="Center"
                                   TextAlignment="Center"/>
                </Grid>
            </Border>
        </Grid>
        <ControlTemplate.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter TargetName="itemBorder"
                            Property="Background"
                            Value="Gray"/>
                <Setter TargetName="itemBorder"
                            Property="BorderBrush"
                            Value="Blue"/>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>

    <ControlTemplate x:Key="MyToggleBtnStyle" 
                         TargetType="ToggleButton">
        <Border Name="MyBorder"
                    Background="AliceBlue"
                    BorderThickness="1" 
                    BorderBrush="Transparent">
            <Path Name="MyPath"
                      Fill="Red"
                      Height="10"
                      Width="10"
                      Data="M5,5 L10,10 L15,5 z"                      
                      Stretch="Fill">
            </Path>
        </Border>
        <ControlTemplate.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter TargetName="MyPath" Property="Fill" Value="Green"></Setter>
                <Setter TargetName="MyBorder" Property="Background" Value="White"></Setter>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>

    <Style x:Key="MyCbbStyle" TargetType="ComboBox">
        <Setter Property="ItemContainerStyle">
            <Setter.Value>
                <Style TargetType="ComboBoxItem">
                    <Setter Property="FontSize" Value="30"/>
                    <Setter Property="Foreground" Value="Blue"/>
                    <Setter Property="Template"
                                Value="{StaticResource MyComboBoxItem}"/>
                </Style>
            </Setter.Value>
        </Setter>

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ComboBox">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="7*"/>
                            <ColumnDefinition Width="3*" MaxWidth="20"/>
                        </Grid.ColumnDefinitions>

                        <Border Grid.Column="0"
                                    BorderBrush="Blue"
                                    BorderThickness="1,1,0,1"
                                    Background="AliceBlue">
                            <ToggleButton Name="togglebutton" Background="{TemplateBinding Background}" VerticalAlignment="Stretch"
                                      Foreground="{TemplateBinding Foreground}"                                     
                                      BorderBrush="#FF045B32" BorderThickness="0"                                      
                                      FontSize="{TemplateBinding FontSize}"                                    
                                      HorizontalContentAlignment="Left"                                   
                                      IsTabStop="False"
                                      Focusable="False"
                                      IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press">
                                <Grid  Height="{Binding Path=ActualHeight, ElementName=togglebutton}"
                                        Width="{Binding Path=ActualWidth, ElementName=togglebutton}">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="*"></ColumnDefinition>
                                        <ColumnDefinition Width="*"></ColumnDefinition>
                                        <ColumnDefinition Width="*"></ColumnDefinition>
                                        <ColumnDefinition Width="*"></ColumnDefinition>
                                    </Grid.ColumnDefinitions>

                                    <Image Grid.Column="0" Source="{TemplateBinding Text,Converter={StaticResource ImageLeftConverter}}"/>
                                    <!--<Path Grid.Column="0" Stroke="Black" StrokeThickness="2" Margin="5" Data="M 0,0  L 0,25  L 25,25  L 25,0 Z"/>-->

                                    <TextBlock Grid.Column="1" Text="{TemplateBinding Text, Converter={StaticResource ComboxLeftStringConverter}}" 
                                       Margin="0,0,0,0"
                                       HorizontalAlignment="Left"
                                       VerticalAlignment="Center"
                                       TextAlignment="Center"/>

                                    <Image Grid.Column="2"  Source="{TemplateBinding Text,Converter={StaticResource ImageRightConverter}}"/>
                                    <!--<Path Grid.Column="2" Stroke="Black" StrokeThickness="2" Margin="5" Data="M 12,12 A 10,10 0 1 1 12,11.9 Z"/>
                                    <Path Grid.Column="2" Stroke="Black" StrokeThickness="2" Margin="0,0,0,0" Data="M 7,5 L 7,30"/>-->

                                    <TextBlock Grid.Column="3" Text="{TemplateBinding Text, Converter={StaticResource ComboxRightStringConverter}}" 
                                       Margin="0,0,0,0"
                                       HorizontalAlignment="Left"
                                       VerticalAlignment="Center"
                                       TextAlignment="Center"/>
                                </Grid>
                            </ToggleButton>
                        </Border>
                        <Border Grid.Column="1"
                                    BorderBrush="Red"
                                    BorderThickness="1">
                            <ToggleButton IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
                                              ClickMode="Press"
                                              Template="{StaticResource MyToggleBtnStyle}"></ToggleButton>
                        </Border>
                        <Popup Name="MyPopup"
                                   IsOpen="{TemplateBinding IsDropDownOpen}"
                                   Placement="Bottom">
                            <Border MinWidth="{TemplateBinding ActualWidth}"
                                        MaxHeight="{TemplateBinding MaxDropDownHeight}">
                                <ScrollViewer MaxHeight="{TemplateBinding MaxDropDownHeight}"
                                                  HorizontalScrollBarVisibility="Auto"
                                                  VerticalScrollBarVisibility="Auto">
                                    <StackPanel Background="AliceBlue"
                                                    IsItemsHost="True"
                                                    />

                                </ScrollViewer>
                            </Border>
                        </Popup>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>
View Code

引用外部资源文件,其命名空间应与工程保持一致,如果还是找不到的话,需要在App.xaml中添加如下代码:

<Application x:Class="PictureCombox.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:PictureCombox"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="CustomDictionary.xaml"></ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>
View Code

MainWindow.xaml代码

<Window x:Class="PictureCombox.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:PictureCombox"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <ComboBox Name="myCbb" DisplayMemberPath="dataAll" Style="{StaticResource MyCbbStyle}" Height="60" Width="250" HorizontalAlignment="Left" VerticalAlignment="Top" SelectedIndex="2"/>
    </Grid>
</Window>
View Code

MainWindow.xaml.cs代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace PictureCombox
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            List<CbbData> cbbDatas = new List<CbbData>();
            for (int i = 0; i < 20; i++)
            {
                CbbData cbbData = new CbbData();
                cbbData.data1 = (i + 1).ToString();
                cbbData.data2 = (i + 2).ToString();
                cbbData.dataAll = (i + 1).ToString() + "," + (i + 2).ToString();
                cbbData.ImgNameLeft = "0";
                cbbData.ImgNameRight = "1";
                cbbDatas.Add(cbbData);
            }

            myCbb.ItemsSource = cbbDatas;
        }
    }
}
View Code

 

有几个关键点需要总结一下:

1.ComboBoxItem自定义就是图片源绑定到ImgNameLeft、ImgNameRight属性,并用转换器将其转换

2.ComboBoxItem自定义数据值绑定到data1、data2属性

3.Combox自定义用ToggleButton替换TextBlock,ToggleButton下面再建Grid子元素,最后将Grid分为4列,每列都绑定到Text,用转换器将其进行转换

注意:MainWindow.xaml中combox元素要添加属性DisplayMemberPath="dataAll",这样style中Text属性相当于是dataAll属性的值,

          style中Grid子元素的大小没有撑满父元素ToggleButton的大小,需要加入以下代码:       

<Grid Height="{Binding Path=ActualHeight, ElementName=togglebutton}"
Width="{Binding Path=ActualWidth, ElementName=togglebutton}">

posted on 2022-11-03 11:13  wu.g.q  阅读(360)  评论(0编辑  收藏  举报

导航