自定义控件在WPF开发中是很常见的,有时候某些控件需要契合业务或者美化统一样式,这时候就需要对控件做出一些改造。

话不多说直接看效果

默认效果:



上传效果:



按钮设置圆角

因为按钮本身没有CornerRadius属性,所以只能重写Button的控件模板。

<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border CornerRadius="5"
Width="{TemplateBinding Width}"
Background="{TemplateBinding Background}"
BorderThickness="1"
Height="{TemplateBinding Height}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

在按钮的模板中加入一个Border即可,但是按钮本身没有CornerRadius属性,就没办法使用TemplateBinding ,只能写死在样式,那肯定不行,所以我们就需要拓展一下Button按钮。

1.创建一个类MyProgressButton继承Button类,由于是新创建的一个类,所以我们可以直接使用依赖属性来完成这件事,在MyProgressButton中定义一个圆角弧度的依赖属性。

public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
} public static readonly DependencyProperty CornerRadiusProperty =
DependencyProperty.Register(nameof(CornerRadius), typeof(CornerRadius), typeof(MyProgressButton), new PropertyMetadata(default));

2.创建一个ProgressButtonStyle.xaml的资源文件,针对MyProgressButton定义一些样式,包括弧度的绑定和鼠标移入移出的阴影效果,让我们的按钮立体起来

<Style TargetType="local:MyProgressButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyProgressButton">
<Border CornerRadius="{TemplateBinding CornerRadius}"
Width="{TemplateBinding Width}"
Background="{TemplateBinding Background}"
BorderThickness="1"
Height="{TemplateBinding Height}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect Color="#cccccc" Direction="270" ShadowDepth="2" Opacity="1" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Effect" >
<Setter.Value>
<DropShadowEffect Color="#bbbbbb" Direction="270" ShadowDepth="2" Opacity="1" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>

3.最后在主界面将MyProgressButton的命名控件加入进来,并且用xaml创建一个MyProgressButton按钮,自定义一些属性,并且将ProgressButtonStyle.xaml样式加入到App.xaml中

<Window x:Class="ProgressButton.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:ProgressButton"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:MyProgressButton Content="上传文件"
Foreground="#555555"
Cursor="Hand"
FontSize="14"
CornerRadius="5"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Height="40" Width="135"
Background="Salmon"
x:Name="upload_btn">
</local:MyProgressButton>
</Grid>
</Window>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/ProgressButton;component/Button/ProgressButtonStyle.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>

看看效果:

按钮上传文件相关定义

1.定义按钮类型MyProgressButton文件上传进度,是否上传,以及上传时按钮背景色三个依赖属性

/// <summary>
/// 文件上传进度
/// </summary>
public double Progress
{
get { return (double)GetValue(ProgressProperty); }
set { SetValue(ProgressProperty, value); }
} public static readonly DependencyProperty ProgressProperty =
DependencyProperty.Register(nameof(Progress), typeof(double), typeof(MyProgressButton), new PropertyMetadata(double.NegativeZero, OnProgressChanged)); /// <summary>
/// 文件是否上传
/// </summary>
public bool IsUploading
{
get { return (bool)GetValue(IsUploadingProperty); }
set { SetValue(IsUploadingProperty, value); }
} public static readonly DependencyProperty IsUploadingProperty =
DependencyProperty.Register(nameof(IsUploading), typeof(bool), typeof(MyProgressButton), new PropertyMetadata(false, OnIsUploadingChanged)); /// <summary>
/// 上传时按钮背景色
/// </summary>
public Color UploadingColor
{
get { return (Color)GetValue(UploadingColorProperty); }
set { SetValue(UploadingColorProperty, value); }
} // Using a DependencyProperty as the backing store for UploadingColor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UploadingColorProperty =
DependencyProperty.Register(nameof(UploadingColor), typeof(Color), typeof(MyProgressButton), new PropertyMetadata(Colors.White));

2.如何实现按钮内部的进度显示?有几种办法,比如使用渐进色修改偏移,或者按钮内部套一个进度条,或者按钮内部放两个不同颜色的块控件,动态修改两者的长度。我们选择第一种。

在Progress属性被修改的时候,我们动态修改下按钮内部渐进色的偏移。为ProgressProperty添加值变化的回调。

private static void OnProgressChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var btn = d as MyProgressButton;
var progress = (double)e.NewValue;
if (progress != double.NegativeZero)
{
Brush brush = null;
if ((brush = btn.Background as LinearGradientBrush) != null) //如果按钮本身是线性渐变色则直接修改偏移
{
GradientStopCollection collections =
brush.GetValue(GradientBrush.GradientStopsProperty) as GradientStopCollection; collections[1].Offset = collections[0].Offset = progress / 100;
}
else //如果本身不是线性渐变色则将背景色修改为线性渐变色
{
LinearGradientBrush linearGradientBrush = new LinearGradientBrush();
//设置一个横向的线
linearGradientBrush.StartPoint = new Point(0, 0.5);
linearGradientBrush.EndPoint = new Point(1, 0.5); GradientStop gradientStop = new GradientStop(); //右边的颜色,即按钮设置的上传时背景色
gradientStop.Color = btn!.UploadingColor; GradientStop gradientStop1 = new GradientStop();//左边的颜色,即按钮原本的颜色
gradientStop1.Color = (btn!.Background as SolidColorBrush)!.Color; gradientStop.Offset = gradientStop1.Offset = progress / 100; linearGradientBrush.GradientStops.Add(gradientStop1);
linearGradientBrush.GradientStops.Add(gradientStop);
btn.Background = linearGradientBrush;
}
}
}

在上传文件的时候,将按钮置为禁用,防止重复点击。写一个IsUploadingProperty属性的值变化的回调。

private static void OnIsUploadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var btn = d as MyProgressButton;
if ((bool)e.NewValue)
{
btn!.IsEnabled = false;
}
else
{
btn!.IsEnabled = true;
}
}
测试代码
Binding binding = new Binding();
binding.Source = this;
binding.Path = new PropertyPath("Progress");
binding.Mode = BindingMode.OneWay;
upload_btn.SetBinding(MyProgressButton.ProgressProperty, binding); Binding binding1 = new Binding();
binding1.Source = this;
binding1.Path = new PropertyPath("IsUploading");
binding1.Mode = BindingMode.OneWay;
upload_btn.SetBinding(MyProgressButton.IsUploadingProperty, binding1);
private async void upload_btn_Click(object sender, RoutedEventArgs e)
{
IsUploading = true;
try
{
using (FileStream fread = new FileStream("d://d3dcompiler_47.dll", FileMode.Open, FileAccess.Read))
using (FileStream fwrite = new FileStream("d://d3dcompiler_47_copy.dll", FileMode.OpenOrCreate, FileAccess.Write))
{
var allLength = new FileInfo("d://d3dcompiler_47.dll").Length;
long copyedBytes = 0;
while (true)
{
var buffer = ArrayPool<byte>.Shared.Rent(1024 * 10);
var len = await fread.ReadAsync(buffer, 0, buffer.Length);
if (len > 0)
{
await fwrite.WriteAsync(buffer[..len]);
copyedBytes += len;
Progress = copyedBytes * 100 / allLength;
await Task.Delay(20);
}
else
{
break;
}
} MessageBox.Show("上传成功");
};
}
catch(Exception ex)
{ }
finally
{
IsUploading = false;
}
}

WFP必须掌握的技能之自定义控件——实战:自制上传文件显示进度按钮的更多相关文章

  1. Postman系列三:Postman中post接口实战(上传文件、json请求)

    一:接口测试过程中GET请求与POST请求的主要区别 从开发角度我们看get与post的主要区别是:1.Get是用来从服务器上获得数据,而Post是用来向服务器上传递数据:2.Get安全性比Post低 ...

  2. [实战]MVC5+EF6+MySql企业网盘实战(4)——上传头像

    写在前面 最近又开始忙了,工期紧比较赶,另外明天又要去驾校,只能一个功能一个功能的添加了,也许每次完成的功能确实不算什么,等将功能都实现了,然后在找一个好点的ui对前端重构一下. 系列文章 [EF]v ...

  3. 《selenium2 python 自动化测试实战》(13)——上传文件

    看代码: # coding: utf-8 from selenium import webdriver from time import sleep driver = webdriver.Firefo ...

  4. Android自定义控件实例,圆形头像(图库 + 裁剪+设置),上传头像显示为圆形,附源码

    Android项目开发中经常会遇见需要实现圆角或者圆形的图片功能,如果仅仅使用系统自带的ImageView控件显然无法实现此功能,所以通过系列文章的形式由简到繁全方位的介绍一下此功能的实现,巩固一下自 ...

  5. 【JavaEE企业应用实战学习记录】servlet3.0上传文件

    <%-- Created by IntelliJ IDEA. User: Administrator Date: 2016/10/6 Time: 14:20 To change this tem ...

  6. Flask实战第57天:UEditor编辑器集成以及配置上传文件到七牛

    相关链接 UEditor:http://ueditor.baidu.com/website/​ 下载地址:http://ueditor.baidu.com/website/download.html# ...

  7. PHP使用FTP上传文件到服务器(实战篇)

    我们在做开发的过程中,上传文件肯定是避免不了的,平常我们的程序和上传的文件都在一个服务器上,我们也可以使用第三方sdk上传文件,但是文件在第三方服务器上.现在我们使用PHP的ftp功能把文件上传到我们 ...

  8. java实用技能 上传文件 等等

    1.IOS  AES对称加密,加密结果不同,问题解决 IOS http post请求,使用AFNetworing 框架,默认请求content-type为application/json ,所以无法使 ...

  9. Selenium 2自动化测试实战18(上传文件)

    一.上传文件 上传文件是比较常见的web功能之一,但WebDriver没有提供专门用于上传的方法. 一般web页面的上传功能的操作需要单击“上传”按钮后打开本地的Window窗口,从窗口选择本地文件进 ...

  10. Day12-微信小程序实战-交友小程序-搭建服务器与上传文件到后端

    要搞一个小型的cms内容发布系统 因为小程序上线之后,直接对数据库进行操作的话,慧出问题的,所以一般都会做一个管理系统,让工作人员通过这个管理系统来对这个数据库进行增删改查 微信小程序其实给我们提供了 ...

随机推荐

  1. GO实现Redis:GO实现内存数据库(3)

    实现Redis的database层(核心层:处理命令并返回) https://github.com/csgopher/go-redis datastruct/dict/dict.go type Con ...

  2. ACM-NEFU-2020大一寒假培训三(暴力)

    A.二倍的问题 Description 给定2到15个不同的正整数,你的任务是计算这些数里面有多少个数对满足:数对中一个数是另一个数的两倍.比如给定1 4 3 2 9 7 18 22,得到的答案是3, ...

  3. 补五月四号java基础知识

    1.在JDK5中新增了自动包装和自动解包功能:当编译器发现程序再应该使用包装类对象的地方却使用基本数据类型的数据时,编译器将自动把该数据包装为该基本数据对应的包装类的对象,这个过程成为自动包装.如类型 ...

  4. day128:MySQL进阶:MySQL安装&用户/权限/连接/配置管理&MySQL的体系结构&SQL&MySQL索引和执行计划

    目录 1.介绍和安装 2.基础管理 2.1 用户管理 2.2 权限管理 2.3 连接管理 2.4 配置管理 3.MySQL的体系结构 4.SQL 5.索引和执行计划 1.介绍和安装 1.1 数据库分类 ...

  5. facebook分享不能显示图片链接问题

    <meta property="og:url" content="http://www.nytimes.com/2015/02/19/arts/internatio ...

  6. Yapi及Swgger使用+注解

    1.Yapi 1.1 介绍 YApi 是高效.易用.功能强大的 api 管理平台,旨在为开发.产品.测试人员提供更优雅的接口管理服务.可以帮助开发者轻松创建.发布.维护 API,YApi 还为用户提供 ...

  7. 基于 Github 平台的 .NET 开源项目模板. 嘎嘎实用!

    简介 大家好,为了使开源项目的维护和管理更方便一些,出于个人需求写了一款开源项目的模板,该模板基于 Github 平台,并使用 .NET 来实现管道功能. 在接受过实战检验后, 于今天开源, 项目地址 ...

  8. HTML中script 标签中的那些属性

    在HTML中, <script> 标签用于嵌入或引用JavaScript代码. 在 <script> 标签中,有两个属性可以用来控制脚本的加载和执行方式: async 和 de ...

  9. ChatGPT在工业领域的研究与应用探索-数据与工况认知

    1.      ChatGPT发展现状... 2 2.      ChatGPT如何与工业相结合... 2 3.      ChatGPT在工业领域的研究与应用... 3 1.   ChatGPT发展 ...

  10. YOLO3论文中文版

    文章目录 YOLO3论文中文版 摘要 1.引言 2. 解决方案 2.1 边界框预测 2.2 类预测 2.3 多尺度预测 2.4 特征提取器 2.5 训练 3.我们的做法 4. 失败的尝试 5.这一切意 ...