系列文章目录
WPF自定义控件与样式(1)-矢量字体图标(iconfont)
WPF自定义控件与样式(3)-TextBox & RichTextBox & PasswordBox样式、水印、Label标签、功能扩展
WPF自定义控件与样式(4)-CheckBox/RadioButton自定义样式
WPF自定义控件与样式(5)-Calendar/DatePicker日期控件自定义样式及扩展
WPF自定义控件与样式(6)-ScrollViewer与ListBox自定义样式
WPF自定义控件与样式(7)-列表控件DataGrid与ListView自定义样式
WPF自定义控件与样式(8)-ComboBox与自定义多选控件MultComboBox
WPF自定义控件与样式(9)-树控件TreeView与菜单Menu-ContextMenu
WPF自定义控件与样式(10)-进度控件ProcessBar自定义样
WPF自定义控件与样式(11)-等待/忙/正在加载状态-控件实现
WPF自定义控件与样式(12)-缩略图ThumbnailImage /gif动画图/图片列表
WPF自定义控件与样式(13)-自定义窗体Window & 自适应内容大小消息框MessageBox
源代码下载地址:https://files.cnblogs.com/files/anding/Util.Controls.zip
Github项目地址:https://github.com/kwonganding/wpf.controls
一.总结.声明
关于本WPF,本人也只能算是一个刚入门的,在学习中和工作中,学习、借鉴了很多网友的文章和开源的项目的知识。发现提供实际项目开发需要的基础控件、样式的文章大都比较散,不成系列。因此基于现在项目中使用的基础UI库,写了这个系列,希望对有需要的人有所帮助。
本系列包括本文共15篇,就到此为止了。关于一些问题再次说明一下:
- 每一篇文章中都给出了基本所有主要代码,目的仅供参考学习,由于目前还是公司在使用中的项目,因此不便提供完整项目源码,有需要的同学还是多动动手吧!
- 对于确实需要源码参考学的,推荐开源项目MahApps.Metro(http://mahapps.com/),我在那里面学习借鉴了很多,本系列中不少样式中都有她(就是她)的影子。
- 本文会把一些额外遗漏的资源或代码一并提供出来
二.附录.本系列补充资源
2.1附加属性
很多样式中使用了附加属性来对基础控件扩展,ControlAttachProperty.cs所有代码:
/// <summary> /// 公共附加属性 /// </summary> public static class ControlAttachProperty { /************************************ Attach Property **************************************/ #region FocusBackground 获得焦点背景色, public static readonly DependencyProperty FocusBackgroundProperty = DependencyProperty.RegisterAttached( "FocusBackground", typeof(Brush), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null)); public static void SetFocusBackground(DependencyObject element, Brush value) { element.SetValue(FocusBackgroundProperty, value); } public static Brush GetFocusBackground(DependencyObject element) { return (Brush)element.GetValue(FocusBackgroundProperty); } #endregion #region FocusForeground 获得焦点前景色, public static readonly DependencyProperty FocusForegroundProperty = DependencyProperty.RegisterAttached( "FocusForeground", typeof(Brush), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null)); public static void SetFocusForeground(DependencyObject element, Brush value) { element.SetValue(FocusForegroundProperty, value); } public static Brush GetFocusForeground(DependencyObject element) { return (Brush)element.GetValue(FocusForegroundProperty); } #endregion #region MouseOverBackgroundProperty 鼠标悬浮背景色 public static readonly DependencyProperty MouseOverBackgroundProperty = DependencyProperty.RegisterAttached( "MouseOverBackground", typeof(Brush), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null)); public static void SetMouseOverBackground(DependencyObject element, Brush value) { element.SetValue(MouseOverBackgroundProperty, value); } public static Brush MouseOverBackground(DependencyObject element) { return (Brush)element.GetValue(FocusBackgroundProperty); } #endregion #region MouseOverForegroundProperty 鼠标悬浮前景色 public static readonly DependencyProperty MouseOverForegroundProperty = DependencyProperty.RegisterAttached( "MouseOverForeground", typeof(Brush), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null)); public static void SetMouseOverForeground(DependencyObject element, Brush value) { element.SetValue(MouseOverForegroundProperty, value); } public static Brush MouseOverForeground(DependencyObject element) { return (Brush)element.GetValue(FocusForegroundProperty); } #endregion #region FocusBorderBrush 焦点边框色,输入控件 public static readonly DependencyProperty FocusBorderBrushProperty = DependencyProperty.RegisterAttached( "FocusBorderBrush", typeof(Brush), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null)); public static void SetFocusBorderBrush(DependencyObject element, Brush value) { element.SetValue(FocusBorderBrushProperty, value); } public static Brush GetFocusBorderBrush(DependencyObject element) { return (Brush)element.GetValue(FocusBorderBrushProperty); } #endregion #region MouseOverBorderBrush 鼠标进入边框色,输入控件 public static readonly DependencyProperty MouseOverBorderBrushProperty = DependencyProperty.RegisterAttached("MouseOverBorderBrush", typeof(Brush), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits)); /// <summary> /// Sets the brush used to draw the mouse over brush. /// </summary> public static void SetMouseOverBorderBrush(DependencyObject obj, Brush value) { obj.SetValue(MouseOverBorderBrushProperty, value); } /// <summary> /// Gets the brush used to draw the mouse over brush. /// </summary> [AttachedPropertyBrowsableForType(typeof(TextBox))] [AttachedPropertyBrowsableForType(typeof(CheckBox))] [AttachedPropertyBrowsableForType(typeof(RadioButton))] [AttachedPropertyBrowsableForType(typeof(DatePicker))] [AttachedPropertyBrowsableForType(typeof(ComboBox))] [AttachedPropertyBrowsableForType(typeof(RichTextBox))] public static Brush GetMouseOverBorderBrush(DependencyObject obj) { return (Brush)obj.GetValue(MouseOverBorderBrushProperty); } #endregion #region AttachContentProperty 附加组件模板 /// <summary> /// 附加组件模板 /// </summary> public static readonly DependencyProperty AttachContentProperty = DependencyProperty.RegisterAttached( "AttachContent", typeof(ControlTemplate), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null)); public static ControlTemplate GetAttachContent(DependencyObject d) { return (ControlTemplate)d.GetValue(AttachContentProperty); } public static void SetAttachContent(DependencyObject obj, ControlTemplate value) { obj.SetValue(AttachContentProperty, value); } #endregion #region WatermarkProperty 水印 /// <summary> /// 水印 /// </summary> public static readonly DependencyProperty WatermarkProperty = DependencyProperty.RegisterAttached( "Watermark", typeof(string), typeof(ControlAttachProperty), new FrameworkPropertyMetadata("")); public static string GetWatermark(DependencyObject d) { return (string)d.GetValue(WatermarkProperty); } public static void SetWatermark(DependencyObject obj, string value) { obj.SetValue(WatermarkProperty, value); } #endregion #region FIconProperty 字体图标 /// <summary> /// 字体图标 /// </summary> public static readonly DependencyProperty FIconProperty = DependencyProperty.RegisterAttached( "FIcon", typeof(string), typeof(ControlAttachProperty), new FrameworkPropertyMetadata("")); public static string GetFIcon(DependencyObject d) { return (string)d.GetValue(FIconProperty); } public static void SetFIcon(DependencyObject obj, string value) { obj.SetValue(FIconProperty, value); } #endregion #region FIconSizeProperty 字体图标大小 /// <summary> /// 字体图标 /// </summary> public static readonly DependencyProperty FIconSizeProperty = DependencyProperty.RegisterAttached( "FIconSize", typeof(double), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(12D)); public static double GetFIconSize(DependencyObject d) { return (double)d.GetValue(FIconSizeProperty); } public static void SetFIconSize(DependencyObject obj, double value) { obj.SetValue(FIconSizeProperty, value); } #endregion #region FIconMarginProperty 字体图标边距 /// <summary> /// 字体图标 /// </summary> public static readonly DependencyProperty FIconMarginProperty = DependencyProperty.RegisterAttached( "FIconMargin", typeof(Thickness), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null)); public static Thickness GetFIconMargin(DependencyObject d) { return (Thickness)d.GetValue(FIconMarginProperty); } public static void SetFIconMargin(DependencyObject obj, Thickness value) { obj.SetValue(FIconMarginProperty, value); } #endregion #region AllowsAnimationProperty 启用旋转动画 /// <summary> /// 启用旋转动画 /// </summary> public static readonly DependencyProperty AllowsAnimationProperty = DependencyProperty.RegisterAttached("AllowsAnimation" , typeof(bool), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(false, AllowsAnimationChanged)); public static bool GetAllowsAnimation(DependencyObject d) { return (bool)d.GetValue(AllowsAnimationProperty); } public static void SetAllowsAnimation(DependencyObject obj, bool value) { obj.SetValue(AllowsAnimationProperty, value); } /// <summary> /// 旋转动画刻度 /// </summary> private static DoubleAnimation RotateAnimation = new DoubleAnimation(0, new Duration(TimeSpan.FromMilliseconds(200))); /// <summary> /// 绑定动画事件 /// </summary> private static void AllowsAnimationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var uc = d as FrameworkElement; if (uc == null) return; if (uc.RenderTransformOrigin == new Point(0, 0)) { uc.RenderTransformOrigin = new Point(0.5, 0.5); RotateTransform trans = new RotateTransform(0); uc.RenderTransform = trans; } var value = (bool)e.NewValue; if (value) { RotateAnimation.To = 180; uc.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, RotateAnimation); } else { RotateAnimation.To = 0; uc.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, RotateAnimation); } } #endregion #region CornerRadiusProperty Border圆角 /// <summary> /// Border圆角 /// </summary> public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.RegisterAttached( "CornerRadius", typeof(CornerRadius), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null)); public static CornerRadius GetCornerRadius(DependencyObject d) { return (CornerRadius)d.GetValue(CornerRadiusProperty); } public static void SetCornerRadius(DependencyObject obj, CornerRadius value) { obj.SetValue(CornerRadiusProperty, value); } #endregion #region LabelProperty TextBox的头部Label /// <summary> /// TextBox的头部Label /// </summary> public static readonly DependencyProperty LabelProperty = DependencyProperty.RegisterAttached( "Label", typeof(string), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null)); [AttachedPropertyBrowsableForType(typeof(TextBox))] public static string GetLabel(DependencyObject d) { return (string)d.GetValue(LabelProperty); } public static void SetLabel(DependencyObject obj, string value) { obj.SetValue(LabelProperty, value); } #endregion #region LabelTemplateProperty TextBox的头部Label模板 /// <summary> /// TextBox的头部Label模板 /// </summary> public static readonly DependencyProperty LabelTemplateProperty = DependencyProperty.RegisterAttached( "LabelTemplate", typeof(ControlTemplate), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null)); [AttachedPropertyBrowsableForType(typeof(TextBox))] public static ControlTemplate GetLabelTemplate(DependencyObject d) { return (ControlTemplate)d.GetValue(LabelTemplateProperty); } public static void SetLabelTemplate(DependencyObject obj, ControlTemplate value) { obj.SetValue(LabelTemplateProperty, value); } #endregion /************************************ RoutedUICommand Behavior enable **************************************/ #region IsClearTextButtonBehaviorEnabledProperty 清除输入框Text值按钮行为开关(设为ture时才会绑定事件) /// <summary> /// 清除输入框Text值按钮行为开关 /// </summary> public static readonly DependencyProperty IsClearTextButtonBehaviorEnabledProperty = DependencyProperty.RegisterAttached("IsClearTextButtonBehaviorEnabled" , typeof(bool), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(false, IsClearTextButtonBehaviorEnabledChanged)); [AttachedPropertyBrowsableForType(typeof(TextBox))] public static bool GetIsClearTextButtonBehaviorEnabled(DependencyObject d) { return (bool)d.GetValue(IsClearTextButtonBehaviorEnabledProperty); } public static void SetIsClearTextButtonBehaviorEnabled(DependencyObject obj, bool value) { obj.SetValue(IsClearTextButtonBehaviorEnabledProperty, value); } /// <summary> /// 绑定清除Text操作的按钮事件 /// </summary> private static void IsClearTextButtonBehaviorEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var button = d as FButton; if (e.OldValue != e.NewValue && button != null) { button.CommandBindings.Add(ClearTextCommandBinding); } } #endregion #region IsOpenFileButtonBehaviorEnabledProperty 选择文件命令行为开关 /// <summary> /// 选择文件命令行为开关 /// </summary> public static readonly DependencyProperty IsOpenFileButtonBehaviorEnabledProperty = DependencyProperty.RegisterAttached("IsOpenFileButtonBehaviorEnabled" , typeof(bool), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(false, IsOpenFileButtonBehaviorEnabledChanged)); [AttachedPropertyBrowsableForType(typeof(TextBox))] public static bool GetIsOpenFileButtonBehaviorEnabled(DependencyObject d) { return (bool)d.GetValue(IsOpenFileButtonBehaviorEnabledProperty); } public static void SetIsOpenFileButtonBehaviorEnabled(DependencyObject obj, bool value) { obj.SetValue(IsOpenFileButtonBehaviorEnabledProperty, value); } private static void IsOpenFileButtonBehaviorEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var button = d as FButton; if (e.OldValue != e.NewValue && button != null) { button.CommandBindings.Add(OpenFileCommandBinding); } } #endregion #region IsOpenFolderButtonBehaviorEnabledProperty 选择文件夹命令行为开关 /// <summary> /// 选择文件夹命令行为开关 /// </summary> public static readonly DependencyProperty IsOpenFolderButtonBehaviorEnabledProperty = DependencyProperty.RegisterAttached("IsOpenFolderButtonBehaviorEnabled" , typeof(bool), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(false, IsOpenFolderButtonBehaviorEnabledChanged)); [AttachedPropertyBrowsableForType(typeof(TextBox))] public static bool GetIsOpenFolderButtonBehaviorEnabled(DependencyObject d) { return (bool)d.GetValue(IsOpenFolderButtonBehaviorEnabledProperty); } public static void SetIsOpenFolderButtonBehaviorEnabled(DependencyObject obj, bool value) { obj.SetValue(IsOpenFolderButtonBehaviorEnabledProperty, value); } private static void IsOpenFolderButtonBehaviorEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var button = d as FButton; if (e.OldValue != e.NewValue && button != null) { button.CommandBindings.Add(OpenFolderCommandBinding); } } #endregion #region IsSaveFileButtonBehaviorEnabledProperty 选择文件保存路径及名称 /// <summary> /// 选择文件保存路径及名称 /// </summary> public static readonly DependencyProperty IsSaveFileButtonBehaviorEnabledProperty = DependencyProperty.RegisterAttached("IsSaveFileButtonBehaviorEnabled" , typeof(bool), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(false, IsSaveFileButtonBehaviorEnabledChanged)); [AttachedPropertyBrowsableForType(typeof(TextBox))] public static bool GetIsSaveFileButtonBehaviorEnabled(DependencyObject d) { return (bool)d.GetValue(IsSaveFileButtonBehaviorEnabledProperty); } public static void SetIsSaveFileButtonBehaviorEnabled(DependencyObject obj, bool value) { obj.SetValue(IsSaveFileButtonBehaviorEnabledProperty, value); } private static void IsSaveFileButtonBehaviorEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var button = d as FButton; if (e.OldValue != e.NewValue && button != null) { button.CommandBindings.Add(SaveFileCommandBinding); } } #endregion /************************************ RoutedUICommand **************************************/ #region ClearTextCommand 清除输入框Text事件命令 /// <summary> /// 清除输入框Text事件命令,需要使用IsClearTextButtonBehaviorEnabledChanged绑定命令 /// </summary> public static RoutedUICommand ClearTextCommand { get; private set; } /// <summary> /// ClearTextCommand绑定事件 /// </summary> private static readonly CommandBinding ClearTextCommandBinding; /// <summary> /// 清除输入框文本值 /// </summary> private static void ClearButtonClick(object sender, ExecutedRoutedEventArgs e) { var tbox = e.Parameter as FrameworkElement; if (tbox == null) return; if (tbox is TextBox) { ((TextBox)tbox).Clear(); } if (tbox is PasswordBox) { ((PasswordBox)tbox).Clear(); } if (tbox is ComboBox) { var cb = tbox as ComboBox; cb.SelectedItem = null; cb.Text = string.Empty; } if (tbox is MultiComboBox) { var cb = tbox as MultiComboBox; cb.SelectedItem = null; cb.UnselectAll(); cb.Text = string.Empty; } if (tbox is DatePicker) { var dp = tbox as DatePicker; dp.SelectedDate = null; dp.Text = string.Empty; } tbox.Focus(); } #endregion #region OpenFileCommand 选择文件命令 /// <summary> /// 选择文件命令,需要使用IsClearTextButtonBehaviorEnabledChanged绑定命令 /// </summary> public static RoutedUICommand OpenFileCommand { get; private set; } /// <summary> /// OpenFileCommand绑定事件 /// </summary> private static readonly CommandBinding OpenFileCommandBinding; /// <summary> /// 执行OpenFileCommand /// </summary> private static void OpenFileButtonClick(object sender, ExecutedRoutedEventArgs e) { var tbox = e.Parameter as FrameworkElement; var txt = tbox as TextBox; string filter = txt.Tag == null ? "所有文件(*.*)|*.*" : txt.Tag.ToString(); if (filter.Contains(".bin")) { filter += "|所有文件(*.*)|*.*"; } if (txt == null) return; OpenFileDialog fd = new OpenFileDialog(); fd.Title = "请选择文件"; //“图像文件(*.bmp, *.jpg)|*.bmp;*.jpg|所有文件(*.*)|*.*” fd.Filter = filter; fd.FileName = txt.Text.Trim(); if (fd.ShowDialog() == true) { txt.Text = fd.FileName; } tbox.Focus(); } #endregion #region OpenFolderCommand 选择文件夹命令 /// <summary> /// 选择文件夹命令 /// </summary> public static RoutedUICommand OpenFolderCommand { get; private set; } /// <summary> /// OpenFolderCommand绑定事件 /// </summary> private static readonly CommandBinding OpenFolderCommandBinding; /// <summary> /// 执行OpenFolderCommand /// </summary> private static void OpenFolderButtonClick(object sender, ExecutedRoutedEventArgs e) { var tbox = e.Parameter as FrameworkElement; var txt = tbox as TextBox; if (txt == null) return; FolderBrowserDialog fd = new FolderBrowserDialog(); fd.Description = "请选择文件路径"; fd.SelectedPath = txt.Text.Trim(); if (fd.ShowDialog() == DialogResult.OK) { txt.Text = fd.SelectedPath; } tbox.Focus(); } #endregion #region SaveFileCommand 选择文件保存路径及名称 /// <summary> /// 选择文件保存路径及名称 /// </summary> public static RoutedUICommand SaveFileCommand { get; private set; } /// <summary> /// SaveFileCommand绑定事件 /// </summary> private static readonly CommandBinding SaveFileCommandBinding; /// <summary> /// 执行OpenFileCommand /// </summary> private static void SaveFileButtonClick(object sender, ExecutedRoutedEventArgs e) { var tbox = e.Parameter as FrameworkElement; var txt = tbox as TextBox; if (txt == null) return; SaveFileDialog fd = new SaveFileDialog(); fd.Title = "文件保存路径"; fd.Filter = "所有文件(*.*)|*.*"; fd.FileName = txt.Text.Trim(); if (fd.ShowDialog() == DialogResult.OK) { txt.Text = fd.FileName; } tbox.Focus(); } #endregion /// <summary> /// 静态构造函数 /// </summary> static ControlAttachProperty() { //ClearTextCommand ClearTextCommand = new RoutedUICommand(); ClearTextCommandBinding = new CommandBinding(ClearTextCommand); ClearTextCommandBinding.Executed += ClearButtonClick; //OpenFileCommand OpenFileCommand = new RoutedUICommand(); OpenFileCommandBinding = new CommandBinding(OpenFileCommand); OpenFileCommandBinding.Executed += OpenFileButtonClick; //OpenFolderCommand OpenFolderCommand = new RoutedUICommand(); OpenFolderCommandBinding = new CommandBinding(OpenFolderCommand); OpenFolderCommandBinding.Executed += OpenFolderButtonClick; SaveFileCommand = new RoutedUICommand(); SaveFileCommandBinding = new CommandBinding(SaveFileCommand); SaveFileCommandBinding.Executed += SaveFileButtonClick; } }