工具代码记录

版权声明:本文为博主初学经验,未经博主允许不得转载。

一、前言

  记录在学习与制作WPF过程中遇到的解决方案。

   分页控件的制作,邮件发送,站点请求代码,excel导入导出等代码的实现过程;

二、配置

系统环境:win10

开发工具:Visual Studio 2017

开发语言:C#.WPF (MVVM框架)

三、功能

  1. 分页控件的制作

1.1 前端xaml代码

<UserControl x:Class="SCB.RPS.Client.Controls.UcPager"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:SCB.RPS.Client.Controls"
mc:Ignorable="d" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="" />
<ColumnDefinition />
<ColumnDefinition Width="" />
<ColumnDefinition />
<ColumnDefinition Width="" />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="" Orientation="Horizontal">
<Label Content="每页显示"/>
<ComboBox Text="{Binding PagerSize}"
            Foreground="Orange" VerticalContentAlignment="Center">
<ComboBoxItem Content=""/>
<ComboBoxItem Content=""/>
<ComboBoxItem Content=""/>
</ComboBox>
<Label Content="项"/>
</StackPanel>
<StackPanel Grid.Column="" Orientation="Horizontal">
<Label Content="当前显示数目:"/>
<Label Content="{Binding PagerRecord}" Foreground="Orange"/>
</StackPanel>
<StackPanel Grid.Column="" Orientation="Horizontal">
<Label Content="查询总量:"/>
<Label Content="{Binding PagerQuantity}" Foreground="Orange"/>
<Label Content="页,共"/>
<Label Content="{Binding TotalRecord}" Foreground="Orange"/>
<Label Content="项"/>
</StackPanel>
<StackPanel Grid.Column=""
             Orientation="Horizontal" VerticalAlignment="Center">
<Button Content="首页" Width="" Height="20"
            Template="{StaticResource DefaultButton}"
            Command="{Binding PagerFirst}"/>
<Button Content="上页" Width="" Height="20"
            Template="{StaticResource DefaultButton}"
            Command="{Binding PagerBefore}" />
<Label Content="{Binding PagerIndex}"
            Foreground="Orange" ToolTip="当前所在页码"/>
<Button Content="下页" Width=""
            Template="{StaticResource DefaultButton}"
            Command="{Binding PagerAfter}" />
<Button Content="末页" Width="" Height="20"
            Template="{StaticResource DefaultButton}"
            Command="{Binding PagerEnd}" />
</StackPanel>
</Grid>
</UserControl>

1.2 style代码

<ControlTemplate TargetType="{x:Type Button}" x:Key="DefaultButton">
<Border BorderBrush="{TemplateBinding Control.BorderBrush}"
       BorderThickness="" Name="btn_modify_bg">
<Border.Background>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#5CACEE" Offset="1.0" />
</LinearGradientBrush>
</Border.Background>
    <ContentPresenter Content="{TemplateBinding ContentControl.Content}"
          HorizontalAlignment="Center" VerticalAlignment="Center" />
  </Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsMouseOver" Value="True">
<Setter Property="Border.Background" TargetName="btn_modify_bg">
<Setter.Value>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#1C86EE" Offset="0.0" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="ButtonBase.IsPressed" Value="True">
<Setter Property="UIElement.Effect">
<Setter.Value>
<DropShadowEffect BlurRadius="" Color="#1C86EE"
                Direction="" Opacity="0.6"
                RenderingBias="Performance" ShadowDepth="" />
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>

1.3 ViewModel业务代码

/// 分页控件 页面模型
public class PagerViewModel : BindableBase
{
//定义一个委托
public delegate void PageChangedHandle(object sender); //上一页下一页的触发事件
public event PageChangedHandle PageChanged; // 默认显示的页容量
public static int DefaultSize = ; public PagerViewModel()
{
PagerFirst = new RelayCommand(PageFirst);
PagerBefore = new RelayCommand(PageBefore);
PagerAfter = new RelayCommand(PageAfter);
PagerEnd = new RelayCommand(PageEnd);
} private int _pagerSize = DefaultSize; //每页容量
private int _pagerIndex = ; //第几页
private int _pagerQuantity; //多少页
private int _pagerRecord; //当前页大小
private int _totalRecord; //总量多少 // 每页容量
public int PagerSize
{
get => _pagerSize;
set
{
_pagerSize = value;
RaisePropertyChanged();
}
} // 第几页
public int PagerIndex
{
get => _pagerIndex;
set
{
_pagerIndex = value;
RaisePropertyChanged();
}
} // 总共有多少页
public int PagerQuantity
{
get => _pagerQuantity;
set
{
_pagerQuantity = value;
RaisePropertyChanged();
}
} // 当前页有多少条数据
public int PagerRecord
{
get => _pagerRecord;
set
{
_pagerRecord = value;
RaisePropertyChanged();
}
} // 查询记录的总量
public int TotalRecord
{
get => _totalRecord;
set
{
_totalRecord = value;
RaisePropertyChanged();
}
} // 首页
public RelayCommand PagerFirst { get; set; } // 上一页
public RelayCommand PagerBefore { get; set; } // 下一页
public RelayCommand PagerAfter { get; set; } // 末页
public RelayCommand PagerEnd { get; set; } // 首页事件
private void PageFirst()
{
PagerIndex = ;
PageChanged?.Invoke();
} // 上一页事件
private void PageBefore()
{
PagerIndex--;
if (PagerIndex < )
{
PagerIndex = ;
MessageBoxHelper.ShowTips("已经是首页");
return;
}
PageChanged?.Invoke(PagerIndex);
} // 下一页事件
private void PageAfter()
{
PagerIndex++;
if (PagerIndex > PagerQuantity)
{
PagerIndex = PagerQuantity;
MessageBoxHelper.ShowTips("已经是末页");
return;
}
PageChanged?.Invoke(PagerIndex);
} // 末页事件
private void PageEnd()
{
PagerIndex = PagerQuantity;
PageChanged?.Invoke(PagerQuantity);
} // 重置分页数据
public void ResetPage()
{
PagerIndex = ;
PagerSize = DefaultSize;
PagerRecord = ;
PagerQuantity = ;
TotalRecord = ;
}
}

MessageBoxHelper.ShowTip 是我封装的弹框提示信息类,等价于MessageBox.Show,只是便于以后统一修改样式或者更改提示信息时的业务处理;

自定义控件不涉及业务逻辑代码,在业务场景使用的时候,需要返回当前页容量、查询总量和查询页数;

PagerView.PagerRecord = result.Count;
PagerView.TotalRecord = result.FirstOrDefault()?.TotalRecord ?? ;
PagerView.PagerQuantity=PagerView.TotalRecord / PagerView.PagerSize + ;

PageChanged是控件的委托方法,在调用该控件时,需绑定委托的事件;

//代码放置在类初始化事件中
PagerView.PageChanged += SearchPageData; //委托给分页控件的查询方法

可以增加比如缓存效果,点击下一页时保存当前页面数据到内存中,重新刷新再清理内存的数据;


private Dictionary<int, List<BatchProductShiftModel>> _tempPage =

          new Dictionary<int, List<BatchProductShiftModel>>(); //列表内容

 private int _tempIndex = 1; //记录当前页

// 分页查询 [加了缓存效果,保存查过的页码数据]
// 缓存后,不会根据选择的页面大小进行调整
// 缓存已处理的数据,点击下一页时,查询总量会产生变化,因为根据条件查询,状态变了
public void SearchPageData(object str)
{
   //记录当前页面数据
_tempPage[_tempIndex] = LstReceiveOrder.ToList();
   //为下次点击分页操作做准备 在内存中记录当前页码
_tempIndex = PagerView.PagerIndex;//判断该页码是否已经在缓存中
if (_tempPage.ContainsKey(PagerView.PagerIndex))
{
LstReceiveOrder.Clear();
     //清理后加载数据
LstReceiveOrder.AddRange(_tempPage[PagerView.PagerIndex]);
//汇总当前页数量
     PagerView.PagerRecord = LstReceiveOrder.Count;
//清理下面明细页的列表内容
     OrderVolumes.Clear();
SelectItemOrder = string.Empty;
}
else SearchProductShiftData(false);
}

LstReceiveOrder 是查询的列表数据;

SearchProductShifData 是查询数据的方法;具体代码不贴了;

OrderVolumes 是明细页,可以去掉该代码;

  2.中文转拼音代码

using System.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Microsoft.International.Converters.PinYinConverter; namespace Common
{
public class PinyinResult
{
public List<string> FirstPingYin { get; set; }
public List<string> FullPingYin { get; set; }
}
/// <summary>
///汉字转为拼音
/// </summary>
public static class PinYinHelper
{
/// <summary>
/// 汉字转为拼音
/// </summary>
/// <param name="str">需要转换的汉字</param>
public static PinyinResult ToPinYin(string str)
{
var chs = str.ToCharArray();
var totalPingYins = new Dictionary<int, List<string>>();
for (int i = ; i < chs.Length; i++)
{
var pinyins = new List<string>();
var ch = chs[i];
//是否是有效的汉字
if (ChineseChar.IsValidChar(ch))
{
var cc = new ChineseChar(ch);
pinyins = cc.Pinyins.Where(
            p => !string.IsNullOrWhiteSpace(p)).ToList();
}
else
pinyins.Add(ch.ToString());
//去除声调,转小写
pinyins = pinyins.ConvertAll(
            p => Regex.Replace(p, @"\d", "").ToLower());
//去重
pinyins = pinyins.Where(p => !string.IsNullOrWhiteSpace(p))
                .Distinct().ToList();
if (pinyins.Any())
totalPingYins[i] = pinyins;
}
var result = new PinyinResult();
foreach (var pinyins in totalPingYins)
{
var items = pinyins.Value;
if (result.FullPingYin==null||result.FullPingYin.Count<=)
{
result.FullPingYin = items;
result.FirstPingYin = items.ConvertAll(
                    p => p.Substring(, ))
                    .Distinct().ToList();
}
else
{
//全拼循环匹配
var newTotalPingYins = new List<string>();
foreach (var totalPingYin in result.FullPingYin)
{
newTotalPingYins.AddRange(
                items.Select(item =>totalPingYin+item));
}
newTotalPingYins = newTotalPingYins.Distinct().ToList();
result.FullPingYin = newTotalPingYins;
//首字母循环匹配
var newFirstPingYins = new List<string>();
foreach (var firstPingYin in result.FirstPingYin)
{
newFirstPingYins.AddRange(
             items.Select(item=>firstPingYin + item.Substring(, )));
}
newFirstPingYins = newFirstPingYins.Distinct().ToList();
result.FirstPingYin = newFirstPingYins;
}
}
return result;
}
}
}

  3.站点请求代码

//添加引用Newtonsoft.Json.dll

// webapi客户端
public class WebApiClient
{
private readonly string _requestUrl;
private readonly string _urlString; // 构造函数
public WebApiClient(string urlString, string requestUrl)
{
_urlString = urlString;
_requestUrl = requestUrl;
} // 发起webapi请求
public T WebApiPost<T>(object value,
        List<Tuple<string, List<string>>> heads = null,
List<string> accepts = null, int timeoutSeconds = )
{
using (var httpClient = new HttpClient())
{
httpClient.Timeout = TimeSpan.FromSeconds(timeoutSeconds);
httpClient.BaseAddress = new Uri(_urlString);
heads?.ForEach(head =>
          httpClient.DefaultRequestHeaders.Add(head.Item1, head.Item2));
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(
          new MediaTypeWithQualityHeaderValue("application/json"));
accepts?.ForEach(
accept => httpClient.DefaultRequestHeaders.Accept.Add(
                  new MediaTypeWithQualityHeaderValue(accept)));
return httpClient.PostAsJsonAsync(_requestUrl, value)
.Result.Content.ReadAsAsync<T>()
.Result;
}
} // 发起webapi请求
public T WebApiGet<T>(List<Tuple<string, List<string>>> heads = null,
List<string> accepts = null, bool isResponseJson = true)
{
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri(_urlString);
heads?.ForEach(head =>
           httpClient.DefaultRequestHeaders.Add(
                      head.Item1, head.Item2));
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(
           new MediaTypeWithQualityHeaderValue("application/json"));
accepts?.ForEach(
accept => httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue(accept)));
if (isResponseJson)
{
return httpClient.GetAsync(_requestUrl)
.Result.Content.ReadAsAsync<T>()
.Result;
}
var content = httpClient.GetAsync(_requestUrl)
.Result.Content.ReadAsStringAsync()
.Result;
return JsonConvert.DeserializeObject<T>(content);
}
} public static T Post<T>(
    string url, object param, string rpsToken = null) where T : class
{
var json = JsonConvert.SerializeObject(param);
var byteData = Encoding.UTF8.GetBytes(json);
var httpRequest = (HttpWebRequest)WebRequest.Create(url);
httpRequest.Method = "POST";
httpRequest.KeepAlive = false;
httpRequest.ContentType = "application/json;charset=utf-8";
if (!string.IsNullOrWhiteSpace(rpsToken))
httpRequest.Headers.Add("RpsToken", rpsToken);
httpRequest.ContentLength = byteData.Length;
httpRequest.GetRequestStream().Write(byteData, , byteData.Length);
httpRequest.Timeout = ;
var strResponse = string.Empty;
Action act = () =>
{
using (var httpResponse = httpRequest.GetResponse())
using (var respStream = httpResponse.GetResponseStream())
using (var reader = new StreamReader(respStream, Encoding.UTF8))
strResponse = reader.ReadToEnd();
};
TryMultiTime(act, );
return JsonConvert.DeserializeObject<T>(strResponse);
} public static void TryMultiTime(
      Action act, int tryTimes, int interval = )
{
var i = ;
while (true)
{
try
{
i++;
act();
break;
}
catch (Exception ex)
{
if (i >= tryTimes)
throw new Exception("请求超时", ex);
System.Threading.Thread.Sleep(interval);
}
}
} /// <summary>
/// 提交带token的请求
/// </summary>
/// <typeparam name="T">返回类型</typeparam>
/// <param name="url">地址</param>
/// <param name="param">json参数</param>
/// <param name="rpsToken">token检验</param>
public static T PostByToken<T>(
    string url, object param, string rpsToken = null) where T : class
{
var json = JsonConvert.SerializeObject(param);
var httpContent = new StringContent(json, Encoding.UTF8);
httpContent.Headers.Add("RpsToken", rpsToken);
httpContent.Headers.ContentType =
              new MediaTypeHeaderValue("application/json");
var response = new HttpClient().PostAsync(url, httpContent);
var strResponse = response.Result.Content.ReadAsStringAsync().Result;
return JsonConvert.DeserializeObject<T>(strResponse);
}
}

  4.邮件发送代码

//使用System.Net.Mail

/// <summary>
/// 发送信息
/// </summary>
public static void SendMessage(string msg = null)
{
try
{
using (var client = new SmtpClient("主机地址", )
{
Credentials = new NetworkCredential("发送人地址", "发送人邮箱密码")
})
{
client.Send(SetMail(msg));
}
}
catch (Exception ex)
{
NLog.Logger.Debug($"异常:{ex.ToJson()}");
}
} /// <summary>
/// 邮件内容
/// </summary>
private static MailMessage SetMail(string msg = null)
{
var fileName =
$"{AppDomain.CurrentDomain.BaseDirectory}/logs/{DateTime.Now:yyyy-MM-dd}.log";
Stream stream = null;
if (File.Exists(fileName))
{
// 打开文件
var fileStream = new FileStream(
      fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
// 读取文件的 byte[]
var bytes = new byte[fileStream.Length];
fileStream.Read(bytes, , bytes.Length);
fileStream.Close();
// 把 byte[] 转换成 Stream
stream = new MemoryStream(bytes);
}
var body = new StringBuilder();
if (!string.IsNullOrWhiteSpace(msg))
     body.AppendFormat("<br/>异常信息:{0};", msg);
var mail = new MailMessage
{
From = new MailAddress("发送人邮箱地址"),
Subject = $"邮件标题",
IsBodyHtml = true,
BodyEncoding = Encoding.UTF8,
Body = body.ToString(),
Priority = MailPriority.High
};
   //添加收件人
BusinessConfiger.MailTo.ForEach(
      to => mail.To.Add(new MailAddress(to)));
if (stream != null)
mail.Attachments.Add(
      new Attachment(stream, $"Log{DateTime.Now:yyyyMMdd}"));
return mail;
}

  5.导入导出代码量过多,直接再下篇源码中体现;

  6.下篇预告

 干货贴代码,包含需求文案、设计思路、简要数据库结构、简要流程图和明细代码,动图细化每步操作,入门级引导文章;

 项目功能包括:登录、首页、数据维护 和 全文搜索等增删查改的常用操作;

WPF项目学习.三的更多相关文章

  1. Spring Boot 项目学习 (三) Spring Boot + Redis 搭建

    0 引言 本文主要介绍 Spring Boot 中 Redis 的配置和基本使用. 1 配置 Redis 1. 修改pom.xml,添加Redis依赖 <!-- Spring Boot Redi ...

  2. 用Visual C++创建WPF项目的三种主要方法

    用Visual C++创建WPF项目的三种主要方法 The problem with using XAML from C++ Because C++ doesn't support partial c ...

  3. WPF项目学习.一

    WPF项目搭建 版权声明:本文为博主初学经验,未经博主允许不得转载. 一.前言 记录在学习与制作WPF过程中遇到的解决方案. 使用MVVM的优点是 数据和视图分离,双向绑定,低耦合,可重用行,相对独立 ...

  4. WPF项目学习.二

    WPF用MVVM的解决记录 版权声明:本文为博主初学经验,未经博主允许不得转载. 一.前言 记录在学习与制作WPF过程中遇到的解决方案.  焦点的控制,键盘事件触发,输入框的数字限制,异步处理,隐藏状 ...

  5. WPF项目学习.四

    信息收录项目 版权声明:本文为博主初学经验,未经博主允许不得转载. 一.前言 记录在学习与制作WPF过程中遇到的解决方案.  需求文案.设计思路.简要数据库结构.简要流程图和明细代码,动图细化每步操作 ...

  6. WPF Binding学习(三)

    转自;http://blog.csdn.net/lisenyang/article/details/18312199 1.控件与控件间的双向绑定 WPF还支持控件作为数据源, <TextBox ...

  7. WPF样式学习三

    SnapsToDevicePixels 获取或设置在呈现过程,该值来确定呈现此元素是否应使用特定于设备的像素设置. 这是一个依赖项属性. true ,如果元素应以符合呈现到设备像素;否则, false ...

  8. Spring Boot 项目学习 (四) Spring Boot整合Swagger2自动生成API文档

    0 引言 在做服务端开发的时候,难免会涉及到API 接口文档的编写,可以经历过手写API 文档的过程,就会发现,一个自动生成API文档可以提高多少的效率. 以下列举几个手写API 文档的痛点: 文档需 ...

  9. Spring Boot 项目学习 (一) 项目搭建

    0 引言 本文主要记录借用Idea 开发环境下,搭建 Spring Boot 项目框架的过程. 1 系列文档目录 Spring Boot 项目学习 (一) 项目搭建 Spring Boot 项目学习 ...

随机推荐

  1. hbase性能调优_表设计案例

    hbase性能调优案例 1.人员-角色   人员有多个角色  角色优先级   角色有多个人员   人员 删除添加角色   角色 可以添加删除人员   人员 角色 删除添加   设计思路 person表 ...

  2. Dig out WeChat deleted chat messages on Android Phone

    As we know that WeChat will wipe deleted chat messages. That's why forensic guys could  not dig out ...

  3. 免费空间上的mysql数据库怎么连接?

    我申请了一个php的免费空间,空间有带mysql数据库,可是我不知道怎么连接. 平时在本地做php时我都是怎么连接的 可是现在到空间上了我就不知道怎么连接了.空间有提供phpmyadmin 会的教一下 ...

  4. github 中删除仓库

    删除时,填充的名字是库的名字

  5. 读书笔记之《Java编程思想》

    17. 容器 Set 存入Set的每个元素都必须是唯一的,因为Set不保存重复元素. Set接口不保证维护元素的次序 Map 映射表(关联数组)的基本思想是维护的是键-值(对)关联,因此可以用键来查找 ...

  6. CSS基础--常用样式

    一.背景相关 背景颜色 background-color :颜色名称/rgb值/十六进制值 背景图片 background-image :url('') 背景图片平铺方式 background-rep ...

  7. 通过Azure 存储账号URL鉴别是标准磁盘还是高性能磁盘

    对于不知道虚拟机磁盘是标准磁盘还是高性能磁盘时,我们可以通过nslookup解析存储账号的URL,来判断存储账号的类型,从而得知虚拟磁盘的类型 1.标准存储账号的解析结果,字母"st&quo ...

  8. 提示让IE8以下版本的浏览器去更新浏览器

    需求: 强制让IE进行页面渲染时候,用最新的方式渲染,并提示让IE8以下的版本去更新浏览器并给一个连接地址 那,如何满足? <!DOCTYPE html> <html lang=&q ...

  9. js_3_for_if_try

    在js中有哪些特殊变量? null 指向一个空地址,一个特殊的地址 var u 定义了一个特殊变量u,类型未定义,boolean(u)=false js中的for循环是什么样子? 对列表: for(v ...

  10. [Qt Quick] qmlscene工具的使用

    qmlscene是Qt 5提供的一个查看qml文件效果的工具.特点是不需要编译应用程序. qmlscene = qml + scene (场景) qmlscene.exe位于Qt的安装目录下 (类似/ ...