彩色图像控件
介绍 本文展示了如何使图像更具自定义性,并提供了许多标准控件的替代方案,这些控件可以在任何地方轻松使用,有时只需一行代码。 假设您具备创建用户控件和转换器的基本知识。您可以参考以下链接以获得关于后者的更多信息: 如何创建一个WPF用户控件&使用它在WPF应用程序(c#)自定义值转换在WPF 预览 表的内容 背景maskedimage maskedbutton maskedtogglebutton maskeddropdownbutton感兴趣的点历史未来 背景 当鼠标悬停在图片上时,我需要改变图片的颜色。这通常是怎么做的?能在几行或更少的篇幅内完成吗? 在发现山那边的草真的更绿之前,我已经得出结论,要做到这一点,唯一的办法就是用黑客或装订的方法。在我试着给那棵树吠叫之前,我一直在寻找更好的解决办法。你瞧,我在StackOverflow上找到了灵感,并把我学到的概念封装到用户控件中。 使用这个新的控件,我可以根据类似的需求和愿望制作另外四个控件。 MaskedImage MaskedImage的目的是获取一个常规图像,并用一种颜色对其进行掩模。颜色掩蔽是可以使用矩形控件和它的OpacityMask属性实现的,这是MaskedImage的大部分组成部分。 示例使用 隐藏,复制Code
<Controls.Common:MaskedImage Source="/Images/Gear.png"/>
属性 源 要屏蔽的图像。 ImageColor 用来遮盖图像的颜色。 ImageWidth 图像的宽度。 ImageHeight 图像的高度。 , 实现 隐藏,收缩,复制Code
public class MaskedImage : UserControl { #region DependencyProperties public static DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(ImageSource), typeof(MaskedImage), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSourceChanged)); public ImageSource Source { get { return (ImageSource)GetValue(SourceProperty); } set { SetValue(SourceProperty, value); } } static void OnSourceChanged(DependencyObject Object, DependencyPropertyChangedEventArgs e) { MaskedImage MaskedImage = Object as MaskedImage; MaskedImage.ImageBrush = new ImageBrush(MaskedImage.Source); } public static DependencyProperty ImageBrushProperty = DependencyProperty.Register("ImageBrush", typeof(ImageBrush), typeof(MaskedImage), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public ImageBrush ImageBrush { get { return (ImageBrush)GetValue(ImageBrushProperty); } private set { SetValue(ImageBrushProperty, value); } } public static readonly DependencyProperty ImageColorProperty = DependencyProperty.Register("ImageColor", typeof(Brush), typeof(MaskedImage), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public Brush ImageColor { get { return (Brush)GetValue(ImageColorProperty); } set { SetValue(ImageColorProperty, value); } } public static DependencyProperty ImageWidthProperty = DependencyProperty.Register("ImageWidth", typeof(double), typeof(MaskedImage), new FrameworkPropertyMetadata(16.0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public double ImageWidth { get { return (double)GetValue(ImageWidthProperty); } set { SetValue(ImageWidthProperty, value); } } public static DependencyProperty ImageHeightProperty = DependencyProperty.Register("ImageHeight", typeof(double), typeof(MaskedImage), new FrameworkPropertyMetadata(16.0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public double ImageHeight { get { return (double)GetValue(ImageHeightProperty); } set { SetValue(ImageHeightProperty, value); } } #endregion #region MaskedImage public MaskedImage() { this.DefaultStyleKey = typeof(MaskedImage); } #endregion }
模板 隐藏,收缩,复制Code
<ControlTemplateTargetType="{x:Type local:MaskedImage}"> <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" Margin="{TemplateBinding Margin}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}"> <Rectangle Width="{TemplateBinding ImageWidth}" Height="{TemplateBinding ImageHeight}" Fill="{TemplateBinding ImageColor}" OpacityMask="{TemplateBinding ImageBrush}"/> </Border> </ControlTemplate>
笔记 将矩形封装在控件中可以在一行中设置图像大小和颜色。 MaskedButton 这里的想法是利用我喜欢的按钮控件的一切,并在此基础上建立一个新的模板。如果我们试图从MaskedImage继承,我们就牺牲了按钮已经定义的基本功能;因此,MaskedButton继承了Button。 示例使用 隐藏,复制Code
<Controls.Common:MaskedButton Source="/Images/Gear.png" Content="Options" DropDownVisibility="Visible" ToolTip="Button tip" DropDownToolTip="Dropdown tip" Click="MaskedButton_Click"> <Controls.Common:MaskedButton.DropDown> <ContextMenu> <MenuItemHeader="Option 1"/> <MenuItemHeader="Option 2"/> <MenuItemHeader="Option 3"/> <MenuItemHeader="Option 4"/> <MenuItemHeader="Option 5"/> <MenuItemHeader="Option 6"/> <MenuItemHeader="Option 7"/> <MenuItemHeader="Option 8"/> </ContextMenu> </Controls.Common:MaskedButton.DropDown> </Controls.Common:MaskedButton>
属性 内容 相对于图像显示的内容。 ContentMargin 保证金为内容。 ContentPlacement 相对于图像的内容位置。 下拉 显示的下拉菜单。 DropDownDataContext 下拉菜单的数据上下文。 DropDownToolTip 下拉按钮的工具提示,独立于主按钮。 DropDownVisibility 获取或设置确定是否应显示下拉按钮的值。 完成 表明checked 状态。 源 要屏蔽的图像。 ImageWidth 掩模图像的宽度。 ImageHeight 掩蔽图像的高度。 ImageColor 掩蔽图像的颜色。 MaskedButton本身只是一个可点击的图像,虽然它也可以有一个下拉菜单,通过设置DropDownVisibility = visibilly . visible。在这种情况下,您有一个可点击的图像和它旁边的一个下拉按钮。点击下拉按钮时激活下拉菜单;当点击时,下拉按钮(默认是一个箭头)使用一个动画旋转,表明菜单是打开的。 考虑下面的例子。 假设你有一个“打开最近的”按钮,可以打开以前打开过的文件。掩码按钮将使您: 当单击主按钮时打开最近打开的文件,并在下拉菜单中显示最近打开的文件列表,单击时每个文件都会打开。 实现 隐藏,收缩,复制Code
public class MaskedButton : Button { #region DependencyProperties public static DependencyProperty ContentMarginProperty = DependencyProperty.Register("ContentMargin", typeof(Thickness), typeof(MaskedButton), new FrameworkPropertyMetadata(default(Thickness), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public Thickness ContentMargin { get { return (Thickness)GetValue(ContentMarginProperty); } set { SetValue(ContentMarginProperty, value); } } public static DependencyProperty ContentPlacementProperty = DependencyProperty.Register("ContentPlacement", typeof(Side), typeof(MaskedButton), new FrameworkPropertyMetadata(Side.Right, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public Side ContentPlacement { get { return (Side)GetValue(ContentPlacementProperty); } set { SetValue(ContentPlacementProperty, value); } } public static readonly DependencyProperty DropDownProperty = DependencyProperty.Register("DropDown", typeof(ContextMenu), typeof(MaskedButton), new UIPropertyMetadata(null, OnDropDownChanged)); public ContextMenu DropDown { get { return (ContextMenu)GetValue(DropDownProperty); } set { SetValue(DropDownProperty, value); } } static void OnDropDownChanged(DependencyObject Object, DependencyPropertyChangedEventArgs e) { MaskedButton MaskedButton = (MaskedButton)Object; if (MaskedButton.DropDown != null) { MaskedButton.DropDown.PlacementTarget = MaskedButton; MaskedButton.DropDown.Placement = PlacementMode.Bottom; if (MaskedButton.DropDownDataContext != null) MaskedButton.DropDown.DataContext = MaskedButton.DropDownDataContext; } } public static DependencyProperty DropDownDataContextProperty = DependencyProperty.Register("DropDownDataContext", typeof(object), typeof(MaskedButton), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnDropDownDataContextChanged)); public object DropDownDataContext { get { return (object)GetValue(DropDownDataContextProperty); } set { SetValue(DropDownDataContextProperty, value); } } static void OnDropDownDataContextChanged(DependencyObject Object, DependencyPropertyChangedEventArgs e) { MaskedButton MaskedButton = (MaskedButton)Object; if (MaskedButton.DropDown != null) MaskedButton.DropDown.DataContext = MaskedButton.DropDownDataContext; } public static DependencyProperty DropDownToolTipProperty = DependencyProperty.Register("DropDownToolTip", typeof(string), typeof(MaskedButton), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public string DropDownToolTip { get { return (string)GetValue(DropDownToolTipProperty); } set { SetValue(DropDownToolTipProperty, value); } } public static DependencyProperty DropDownVisibilityProperty = DependencyProperty.Register("DropDownVisibility", typeof(Visibility), typeof(MaskedButton), new FrameworkPropertyMetadata(Visibility.Collapsed, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public Visibility DropDownVisibility { get { return (Visibility)GetValue(DropDownVisibilityProperty); } set { SetValue(DropDownVisibilityProperty, value); } } public static DependencyProperty IsCheckedProperty = DependencyProperty.Register("IsChecked", typeof(bool), typeof(MaskedButton), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public bool IsChecked { get { return (bool)GetValue(IsCheckedProperty); } set { SetValue(IsCheckedProperty, value); } } public static DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(ImageSource), typeof(MaskedButton), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSourceChanged)); public ImageSource Source { get { return (ImageSource)GetValue(SourceProperty); } set { SetValue(SourceProperty, value); } } private static void OnSourceChanged(DependencyObject Object, DependencyPropertyChangedEventArgs e) { MaskedButton Button = Object as MaskedButton; Button.ImageBrush = new ImageBrush(Button.Source); } public static DependencyProperty ImageBrushProperty = DependencyProperty.Register("ImageBrush", typeof(ImageBrush), typeof(MaskedButton), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public ImageBrush ImageBrush { get { return (ImageBrush)GetValue(ImageBrushProperty); } set { SetValue(ImageBrushProperty, value); } } public static readonly DependencyProperty ImageColorProperty = DependencyProperty.Register("ImageColor", typeof(Brush), typeof(MaskedButton), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public Brush ImageColor { get { return (Brush)GetValue(ImageColorProperty); } set { SetValue(ImageColorProperty, value); } } public static DependencyProperty ImageWidthProperty = DependencyProperty.Register("ImageWidth", typeof(double), typeof(MaskedButton), new FrameworkPropertyMetadata(16.0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public double ImageWidth { get { return (double)GetValue(ImageWidthProperty); } set { SetValue(ImageWidthProperty, value); } } public static DependencyProperty ImageHeightProperty = DependencyProperty.Register("ImageHeight", typeof(double), typeof(MaskedButton), new FrameworkPropertyMetadata(16.0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public double ImageHeight { get { return (double)GetValue(ImageHeightProperty); } set { SetValue(ImageHeightProperty, value); } } #endregion #region MaskedButton public MaskedButton() { this.DefaultStyleKey = typeof(MaskedButton); this.ContentMargin = new Thickness(5, 0, 0, 0); } public override void OnApplyTemplate() { base.ApplyTemplate(); this.Template.FindName("PART_Dropdown", this).As<ContentControl>().MouseLeftButtonDown += OnDropdownMouseLeftButtonDown; } #endregion #region Methods protected override void OnMouseDown(MouseButtonEventArgs e) { base.OnMouseDown(e); if (e.Handled) return; } void OnDropdownMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { e.Handled = true; if (this.DropDown != null) this.DropDown.IsOpen = true; } #endregion }
模板 隐藏,收缩,复制Code
<ControlTemplateTargetType="{x:Type local:MaskedButton}"> <Border Margin="{TemplateBinding Margin}" Padding="{TemplateBinding Padding}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}"> <Grid> <Grid.RowDefinitions> <RowDefinitionHeight="Auto"/> <RowDefinitionHeight="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinitionWidth="Auto"/> <ColumnDefinitionWidth="Auto"/> <ColumnDefinitionWidth="Auto"/> </Grid.ColumnDefinitions> <local:MaskedImage x:Name="PART_Rectangle" Source="{TemplateBinding Source}" ImageWidth="{TemplateBinding ImageWidth}" ImageHeight="{TemplateBinding ImageHeight}" ImageColor="{TemplateBinding ImageColor}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Visibility="{TemplateBinding Source, Converter={StaticResource NullObjectToVisibilityConverter}}"/> <ContentControl Grid.Column="1" x:Name="PART_Content" Content="{TemplateBinding Content}" Margin="{TemplateBinding ContentMargin}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Visibility="{TemplateBinding Content, Converter={StaticResource NullObjectToVisibilityConverter}}"/> <ContentControl Grid.Column="2" x:Name="PART_Dropdown" Margin="5,0,0,0" Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:MaskedButton}}}" ToolTip="{TemplateBinding DropDownToolTip}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Visibility="{TemplateBinding DropDownVisibility}"> <ContentControl.Style> <StyleTargetType="{x:Type ContentControl}"> <SetterProperty="Cursor"Value="Hand"/> <SetterProperty="Template"> <Setter.Value> <ControlTemplateTargetType="{x:Type ContentControl}"> <Rectanglex:Name="PART_Rectangle"Width="12"Height="12"RenderTransformOrigin="0.5,0.5"> <Rectangle.OpacityMask> <ImageBrushImageSource="pack://application:,,,/Imagin.Controls.Common;component/Images/ArrowDown.png"/> </Rectangle.OpacityMask> <Rectangle.RenderTransform> <RotateTransformAngle="-90"/> </Rectangle.RenderTransform> </Rectangle> <ControlTemplate.Triggers> <DataTriggerBinding="{Binding IsChecked, RelativeSource={RelativeSource AncestorType={x:Type local:MaskedButton}}}"Value="True"> <DataTrigger.EnterActions> <BeginStoryboard> <Storyboard> <DoubleAnimation Duration="0:0:0.25" Storyboard.TargetName="PART_Rectangle" Storyboard.TargetProperty="RenderTransform.Angle" From="-90" To="0"/> </Storyboard> </BeginStoryboard> </DataTrigger.EnterActions> <DataTrigger.ExitActions> <BeginStoryboard> <Storyboard> <DoubleAnimation Duration="0:0:0.25" Storyboard.TargetName="PART_Rectangle" Storyboard.TargetProperty="RenderTransform.Angle" From="0" To="-90"/> </Storyboard> </BeginStoryboard> </DataTrigger.ExitActions> <SetterTargetName="PART_Rectangle"Property="Fill"Value="{DynamicResource ImagePressedBrush}"/> </DataTrigger> <DataTriggerBinding="{Binding IsChecked, RelativeSource={RelativeSource AncestorType={x:Type local:MaskedButton}}}"Value="False"> <SetterTargetName="PART_Rectangle"Property="Fill"Value="{DynamicResource ImageBrush}"/> </DataTrigger> <TriggerProperty="IsMouseOver"Value="True"> <SetterTargetName="PART_Rectangle"Property="Fill"Value="{DynamicResource ImageHoverBrush}"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </ContentControl.Style> </ContentControl> </Grid> </Border> <ControlTemplate.Triggers> <TriggerProperty="ContentPlacement"Value="Top"> <SetterTargetName="PART_Rectangle"Property="Grid.Column"Value="0"/> <SetterTargetName="PART_Content"Property="Grid.Column"Value="0"/> <SetterTargetName="PART_Rectangle"Property="Grid.ColumnSpan"Value="2"/> <SetterTargetName="PART_Content"Property="Grid.ColumnSpan"Value="2"/> <SetterTargetName="PART_Rectangle"Property="Grid.Row"Value="1"/> <SetterTargetName="PART_Content"Property="Grid.Row"Value="0"/> <SetterTargetName="PART_Rectangle"Property="Grid.RowSpan"Value="1"/> <SetterTargetName="PART_Content"Property="Grid.RowSpan"Value="1"/> </Trigger> <TriggerProperty="ContentPlacement"Value="Bottom"> <SetterTargetName="PART_Rectangle"Property="Grid.Column"Value="0"/> <SetterTargetName="PART_Content"Property="Grid.Column"Value="0"/> <SetterTargetName="PART_Rectangle"Property="Grid.ColumnSpan"Value="2"/> <SetterTargetName="PART_Content"Property="Grid.ColumnSpan"Value="2"/> <SetterTargetName="PART_Rectangle"Property="Grid.Row"Value="0"/> <SetterTargetName="PART_Content"Property="Grid.Row"Value="1"/> <SetterTargetName="PART_Rectangle"Property="Grid.RowSpan"Value="1"/> <SetterTargetName="PART_Content"Property="Grid.RowSpan"Value="1"/> </Trigger> <TriggerProperty="ContentPlacement"Value="Left"> <SetterTargetName="PART_Rectangle"Property="Grid.Column"Value="1"/> <SetterTargetName="PART_Content"Property="Grid.Column"Value="0"/> <SetterTargetName="PART_Rectangle"Property="Grid.ColumnSpan"Value="1"/> <SetterTargetName="PART_Content"Property="Grid.ColumnSpan"Value="1"/> <SetterTargetName="PART_Rectangle"Property="Grid.Row"Value="0"/> <SetterTargetName="PART_Content"Property="Grid.Row"Value="0"/> <SetterTargetName="PART_Rectangle"Property="Grid.RowSpan"Value="2"/> <SetterTargetName="PART_Content"Property="Grid.RowSpan"Value="2"/> </Trigger> <TriggerProperty="ContentPlacement"Value="Right"> <SetterTargetName="PART_Rectangle"Property="Grid.Column"Value="0"/> <SetterTargetName="PART_Content"Property="Grid.Column"Value="1"/> <SetterTargetName="PART_Rectangle"Property="Grid.ColumnSpan"Value="1"/> <SetterTargetName="PART_Content"Property="Grid.ColumnSpan"Value="1"/> <SetterTargetName="PART_Rectangle"Property="Grid.Row"Value="0"/> <SetterTargetName="PART_Content"Property="Grid.Row"Value="0"/> <SetterTargetName="PART_Rectangle"Property="Grid.RowSpan"Value="2"/> <SetterTargetName="PART_Content"Property="Grid.RowSpan"Value="2"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate>
笔记 在解决一个可视父对象的数据上下文时遇到麻烦;一个技巧是将它的数据上下文绑定到它的放置目标或任何放置目标的属性。属性DropDownDataContext 为您设置数据上下文,并消除了显式定义数据上下文的需要。 MaskedToggleButton MaskedToggleButton继承……你猜对了,ToggleButton。除了图片的颜色可以切换和支持分组(类似于RadioButton分组)之外,功能是相同的。 示例使用 隐藏,复制Code
<Controls.Common:MaskedToggleButton Source="/Images/Gear.png" Content="Options" CheckedToolTip="Options are checked" UncheckedToolTip="Options are not checked"/>
属性 源 要屏蔽的图像。 ImageWidth 掩模图像的宽度。 ImageHeight 掩蔽图像的高度。 ImageColor 掩蔽图像的颜色。 GroupName 通过确保只检查共享面板中名称匹配的一个项来启用分组。 完成 表明checked 状态。 CheckedToolTip 选中按钮时要显示的工具提示 UncheckedToolTip 当按钮未被选中时要显示的工具提示 工具提示 不应该是你sed。 内容 相对于图像显示的内容。 ContentMargin 保证金为内容。 ContentPlacement 相对于图像的内容位置。 实现 隐藏,收缩,复制Code
public class MaskedToggleButton : ToggleButton { #region DependencyProperties public static DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(ImageSource), typeof(MaskedToggleButton), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSourceChanged)); public ImageSource Source { get { return (ImageSource)GetValue(SourceProperty); } set { SetValue(SourceProperty, value); } } private static void OnSourceChanged(DependencyObject Object, DependencyPropertyChangedEventArgs e) { MaskedToggleButton MaskedToggleButton = Object as MaskedToggleButton; MaskedToggleButton.ImageBrush = new ImageBrush(MaskedToggleButton.Source); } public static DependencyProperty ImageBrushProperty = DependencyProperty.Register("ImageBrush", typeof(ImageBrush), typeof(MaskedToggleButton), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public ImageBrush ImageBrush { get { return (ImageBrush)GetValue(ImageBrushProperty); } set { SetValue(ImageBrushProperty, value); } } public static readonly DependencyProperty ImageColorProperty = DependencyProperty.Register("ImageColor", typeof(Brush), typeof(MaskedToggleButton), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public Brush ImageColor { get { return (Brush)GetValue(ImageColorProperty); } set { SetValue(ImageColorProperty, value); } } public static DependencyProperty GroupNameProperty = DependencyProperty.Register("GroupName", typeof(string), typeof(MaskedToggleButton), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnGroupNameChanged)); public string GroupName { get { return (string)GetValue(GroupNameProperty); } set { SetValue(GroupNameProperty, value); } } private static void OnGroupNameChanged(DependencyObject Object, DependencyPropertyChangedEventArgs e) { MaskedToggleButton MaskedToggleButton = Object as MaskedToggleButton; if (MaskedToggleButton.GroupName == string.Empty) { MaskedToggleButton.Checked -= MaskedToggleButton.MaskedToggleButton_Checked; } else { MaskedToggleButton.Checked += MaskedToggleButton.MaskedToggleButton_Checked; } } private void MaskedToggleButton_Checked(object sender, EventArgs e) { //We only want to affect the other values if current is true. This avoids other controls from attempting to execute same method when their values have changed. //In order for this to work, all controls sharing same group name should be in same parent. DependencyObject Parent = this.FindParent<DependencyObject>(this); for (int i = 0, Count = VisualTreeHelper.GetChildrenCount(Parent); i < Count; i++) { var Child = VisualTreeHelper.GetChild(Parent, i); if (!(Child is MaskedToggleButton)) continue; //If it's not same type of control, skip it MaskedToggleButton Button = Child as MaskedToggleButton; if (Button == this) continue; //If we're at this, skip it Button.IsChecked = false; //If it's not this, we'll want to uncheck it. } } public static DependencyProperty CheckedToolTipProperty = DependencyProperty.Register("CheckedToolTip", typeof(string), typeof(MaskedToggleButton), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public string CheckedToolTip { get { return (string)GetValue(CheckedToolTipProperty); } set { SetValue(CheckedToolTipProperty, value); } } public static DependencyProperty UncheckedToolTipProperty = DependencyProperty.Register("UncheckedToolTip", typeof(string), typeof(MaskedToggleButton), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public string UncheckedToolTip { get { return (string)GetValue(UncheckedToolTipProperty); } set { SetValue(UncheckedToolTipProperty, value); } } public static DependencyProperty ImageWidthProperty = DependencyProperty.Register("ImageWidth", typeof(double), typeof(MaskedToggleButton), new FrameworkPropertyMetadata(16.0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public double ImageWidth { get { return (double)GetValue(ImageWidthProperty); } set { SetValue(ImageWidthProperty, value); } } public static DependencyProperty ImageHeightProperty = DependencyProperty.Register("ImageHeight", typeof(double), typeof(MaskedToggleButton), new FrameworkPropertyMetadata(16.0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public double ImageHeight { get { return (double)GetValue(ImageHeightProperty); } set { SetValue(ImageHeightProperty, value); } } public static DependencyProperty ContentMarginProperty = DependencyProperty.Register("ContentMargin", typeof(Thickness), typeof(MaskedToggleButton), new FrameworkPropertyMetadata(default(Thickness), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public Thickness ContentMargin { get { return (Thickness)GetValue(ContentMarginProperty); } set { SetValue(ContentMarginProperty, value); } } public static DependencyProperty ContentPlacementProperty = DependencyProperty.Register("ContentPlacement", typeof(Side), typeof(MaskedToggleButton), new FrameworkPropertyMetadata(Side.Right, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public Side ContentPlacement { get { return (Side)GetValue(ContentPlacementProperty); } set { SetValue(ContentPlacementProperty, value); } } #endregion #region Methods private T FindParent<T>(DependencyObject child) where T : DependencyObject { DependencyObject parentObject = VisualTreeHelper.GetParent(child); //Get parent item if (parentObject == null) return null; //We've reached the end of the tree T parent = parentObject as T; //Check if the parent matches the type we're looking for if (parent != null) return parent; else return FindParent<T>(parentObject); } public void SetGroup() { } #endregion #region MaskedToggleButton public MaskedToggleButton() { this.DefaultStyleKey = typeof(MaskedToggleButton); this.ContentMargin = new Thickness(5, 0, 0, 0); } #endregion }
模板 隐藏,收缩,复制Code
<ControlTemplateTargetType="{x:Type local:MaskedToggleButton}"> <Border Margin="{TemplateBinding Margin}" Padding="{TemplateBinding Padding}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"> <Grid> <Grid.RowDefinitions> <RowDefinitionHeight="Auto"/> <RowDefinitionHeight="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinitionWidth="Auto"/> <ColumnDefinitionWidth="Auto"/> </Grid.ColumnDefinitions> <local:MaskedImage x:Name="PART_Rectangle" Margin="0" Padding="0" Source="{TemplateBinding Source}" ImageWidth="{TemplateBinding ImageWidth}" ImageHeight="{TemplateBinding ImageHeight}" ImageColor="{TemplateBinding ImageColor}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Visibility="{TemplateBinding Source, Converter={StaticResource NullObjectToVisibilityConverter}}"/> <ContentPresenter Grid.Column="1" x:Name="PART_Content" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" Margin="{TemplateBinding ContentMargin}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Visibility="{TemplateBinding Content, Converter={StaticResource NullObjectToVisibilityConverter}}"/> </Grid> </Border> <ControlTemplate.Triggers> <TriggerProperty="ContentPlacement"Value="Top"> <SetterTargetName="PART_Rectangle"Property="Grid.Column"Value="0"/> <SetterTargetName="PART_Content"Property="Grid.Column"Value="0"/> <SetterTargetName="PART_Rectangle"Property="Grid.ColumnSpan"Value="2"/> <SetterTargetName="PART_Content"Property="Grid.ColumnSpan"Value="2"/> <SetterTargetName="PART_Rectangle"Property="Grid.Row"Value="1"/> <SetterTargetName="PART_Content"Property="Grid.Row"Value="0"/> <SetterTargetName="PART_Rectangle"Property="Grid.RowSpan"Value="1"/> <SetterTargetName="PART_Content"Property="Grid.RowSpan"Value="1"/> </Trigger> <TriggerProperty="ContentPlacement"Value="Bottom"> <SetterTargetName="PART_Rectangle"Property="Grid.Column"Value="0"/> <SetterTargetName="PART_Content"Property="Grid.Column"Value="0"/> <SetterTargetName="PART_Rectangle"Property="Grid.ColumnSpan"Value="2"/> <SetterTargetName="PART_Content"Property="Grid.ColumnSpan"Value="2"/> <SetterTargetName="PART_Rectangle"Property="Grid.Row"Value="0"/> <SetterTargetName="PART_Content"Property="Grid.Row"Value="1"/> <SetterTargetName="PART_Rectangle"Property="Grid.RowSpan"Value="1"/> <SetterTargetName="PART_Content"Property="Grid.RowSpan"Value="1"/> </Trigger> <TriggerProperty="ContentPlacement"Value="Left"> <SetterTargetName="PART_Rectangle"Property="Grid.Column"Value="1"/> <SetterTargetName="PART_Content"Property="Grid.Column"Value="0"/> <SetterTargetName="PART_Rectangle"Property="Grid.ColumnSpan"Value="1"/> <SetterTargetName="PART_Content"Property="Grid.ColumnSpan"Value="1"/> <SetterTargetName="PART_Rectangle"Property="Grid.Row"Value="0"/> <SetterTargetName="PART_Content"Property="Grid.Row"Value="0"/> <SetterTargetName="PART_Rectangle"Property="Grid.RowSpan"Value="2"/> <SetterTargetName="PART_Content"Property="Grid.RowSpan"Value="2"/> </Trigger> <TriggerProperty="ContentPlacement"Value="Right"> <SetterTargetName="PART_Rectangle"Property="Grid.Column"Value="0"/> <SetterTargetName="PART_Content"Property="Grid.Column"Value="1"/> <SetterTargetName="PART_Rectangle"Property="Grid.ColumnSpan"Value="1"/> <SetterTargetName="PART_Content"Property="Grid.ColumnSpan"Value="1"/> <SetterTargetName="PART_Rectangle"Property="Grid.Row"Value="0"/> <SetterTargetName="PART_Content"Property="Grid.Row"Value="0"/> <SetterTargetName="PART_Rectangle"Property="Grid.RowSpan"Value="2"/> <SetterTargetName="PART_Content"Property="Grid.RowSpan"Value="2"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate>
MaskedDropDownButton MaskedDropDownButton继承MaskedToggleButton,但intead只是切换图像的颜色,它显示一个下拉菜单出现在检查状态。 示例使用 隐藏,复制Code
<Controls.Common:MaskedDropDownButton Source="/Images/Gear.png" Content="Options"> <Controls.Common:MaskedDropDownButton.DropDown> <ContextMenu> <MenuItemHeader="Option 1"/> <MenuItemHeader="Option 2"/> <MenuItemHeader="Option 3"/> <MenuItemHeader="Option 4"/> <MenuItemHeader="Option 5"/> </ContextMenu> </Controls.Common:MaskedDropDownButton.DropDown> </Controls.Common:MaskedDropDownButton>
属性 下拉 下拉菜单。 DropDownDataContext 下拉菜单的数据上下文。 实现 隐藏,收缩,复制Code
public class MaskedDropDownButton : MaskedToggleButton { #region Properties public static readonly DependencyProperty DropDownProperty = DependencyProperty.Register("DropDown", typeof(ContextMenu), typeof(MaskedDropDownButton), new UIPropertyMetadata(null, OnDropDownChanged)); public ContextMenu DropDown { get { return (ContextMenu)GetValue(DropDownProperty); } set { SetValue(DropDownProperty, value); } } static void OnDropDownChanged(DependencyObject Object, DependencyPropertyChangedEventArgs e) { MaskedDropDownButton MaskedDropDownButton = (MaskedDropDownButton)Object; if (MaskedDropDownButton.DropDown != null) { MaskedDropDownButton.DropDown.PlacementTarget = MaskedDropDownButton; MaskedDropDownButton.DropDown.Placement = PlacementMode.Bottom; if (MaskedDropDownButton.DropDownDataContext != null) MaskedDropDownButton.DropDown.DataContext = MaskedDropDownButton.DropDownDataContext; } } public static DependencyProperty DropDownDataContextProperty = DependencyProperty.Register("DropDownDataContext", typeof(object), typeof(MaskedDropDownButton), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnDropDownDataContextChanged)); public object DropDownDataContext { get { return (object)GetValue(DropDownDataContextProperty); } set { SetValue(DropDownDataContextProperty, value); } } static void OnDropDownDataContextChanged(DependencyObject Object, DependencyPropertyChangedEventArgs e) { MaskedDropDownButton MaskedDropDownButton = (MaskedDropDownButton)Object; if (MaskedDropDownButton.DropDown != null) MaskedDropDownButton.DropDown.DataContext = MaskedDropDownButton.DropDownDataContext; } #endregion #region MaskedDropDownButton public MaskedDropDownButton() { this.DefaultStyleKey = typeof(MaskedDropDownButton); this.ContentMargin = new Thickness(5, 0, 0, 0); this.SetBinding(MaskedDropDownButton.IsCheckedProperty, new Binding("DropDown.IsOpen") { Source = this }); this.SetBinding(MaskedDropDownButton.DropDownDataContextProperty, new Binding("DropDown.DataContext") { Source = this }); } #endregion #region Methods protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { e.Handled = true; if (this.DropDown != null) this.DropDown.IsOpen = true; } #endregion }
模板 隐藏,收缩,复制Code
<ControlTemplateTargetType="{x:Type local:MaskedDropDownButton}"> <Border Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Margin="{TemplateBinding Margin}" Padding="{TemplateBinding Padding}"> <Grid> <Grid.RowDefinitions> <RowDefinitionHeight="Auto"/> <RowDefinitionHeight="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinitionWidth="Auto"/> <ColumnDefinitionWidth="Auto"/> </Grid.ColumnDefinitions> <local:MaskedImage x:Name="PART_Rectangle" Source="{TemplateBinding Source}" ImageWidth="{TemplateBinding ImageWidth}" ImageHeight="{TemplateBinding ImageHeight}" ImageColor="{TemplateBinding ImageColor}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Visibility="{TemplateBinding Source, Converter={StaticResource NullObjectToVisibilityConverter}}"/> <ContentControl Grid.Column="1" x:Name="PART_Content" Content="{TemplateBinding Content}" Margin="{TemplateBinding ContentMargin}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Visibility="{TemplateBinding Content, Converter={StaticResource NullObjectToVisibilityConverter}}"/> </Grid> </Border> <ControlTemplate.Triggers> <TriggerProperty="ContentPlacement"Value="Top"> <SetterTargetName="PART_Rectangle"Property="Grid.Column"Value="0"/> <SetterTargetName="PART_Content"Property="Grid.Column"Value="0"/> <SetterTargetName="PART_Rectangle"Property="Grid.ColumnSpan"Value="2"/> <SetterTargetName="PART_Content"Property="Grid.ColumnSpan"Value="2"/> <SetterTargetName="PART_Rectangle"Property="Grid.Row"Value="1"/> <SetterTargetName="PART_Content"Property="Grid.Row"Value="0"/> <SetterTargetName="PART_Rectangle"Property="Grid.RowSpan"Value="1"/> <SetterTargetName="PART_Content"Property="Grid.RowSpan"Value="1"/> </Trigger> <TriggerProperty="ContentPlacement"Value="Bottom"> <SetterTargetName="PART_Rectangle"Property="Grid.Column"Value="0"/> <SetterTargetName="PART_Content"Property="Grid.Column"Value="0"/> <SetterTargetName="PART_Rectangle"Property="Grid.ColumnSpan"Value="2"/> <SetterTargetName="PART_Content"Property="Grid.ColumnSpan"Value="2"/> <SetterTargetName="PART_Rectangle"Property="Grid.Row"Value="0"/> <SetterTargetName="PART_Content"Property="Grid.Row"Value="1"/> <SetterTargetName="PART_Rectangle"Property="Grid.RowSpan"Value="1"/> <SetterTargetName="PART_Content"Property="Grid.RowSpan"Value="1"/> </Trigger> <TriggerProperty="ContentPlacement"Value="Left"> <SetterTargetName="PART_Rectangle"Property="Grid.Column"Value="1"/> <SetterTargetName="PART_Content"Property="Grid.Column"Value="0"/> <SetterTargetName="PART_Rectangle"Property="Grid.ColumnSpan"Value="1"/> <SetterTargetName="PART_Content"Property="Grid.ColumnSpan"Value="1"/> <SetterTargetName="PART_Rectangle"Property="Grid.Row"Value="0"/> <SetterTargetName="PART_Content"Property="Grid.Row"Value="0"/> <SetterTargetName="PART_Rectangle"Property="Grid.RowSpan"Value="2"/> <SetterTargetName="PART_Content"Property="Grid.RowSpan"Value="2"/> </Trigger> <TriggerProperty="ContentPlacement"Value="Right"> <SetterTargetName="PART_Rectangle"Property="Grid.Column"Value="0"/> <SetterTargetName="PART_Content"Property="Grid.Column"Value="1"/> <SetterTargetName="PART_Rectangle"Property="Grid.ColumnSpan"Value="1"/> <SetterTargetName="PART_Content"Property="Grid.ColumnSpan"Value="1"/> <SetterTargetName="PART_Rectangle"Property="Grid.Row"Value="0"/> <SetterTargetName="PART_Content"Property="Grid.Row"Value="0"/> <SetterTargetName="PART_Rectangle"Property="Grid.RowSpan"Value="2"/> <SetterTargetName="PART_Content"Property="Grid.RowSpan"Value="2"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate>
笔记 什么使MaskedDropDownButton很好的是改变图像的颜色时,下拉菜单显示的能力。 的兴趣点 控件的边框、填充、边距、宽度和高度可以与被遮罩的图像分开设置。触发器用于通过设置受影响元素的行和列来确定内容相对于屏蔽图像的位置。 历史 2016年5月29日 最初的帖子。 2016年6月1日 将先前的多个物品组合成一个。 2016年8月17日 AdvancedImageDropDownButton的模板不再包含下拉按钮,而是使用ContentControl来显示旋转箭头。这使得下拉菜单可以直接显示在整个控件的下方,而不是直接显示在箭头按钮的下方。这也使得将下拉列表的放置目标绑定到下拉列表的数据上下文成为可能,这在绑定到ContextMenu时是非常必要的。 9月6日 更新文章。 未来 本文中的代码现在是开源项目Imagin.NET. 的一部分。 本文转载于:http://www.diyabc.com/frontweb/news449.html