• WPF项目学习.三


    工具代码记录

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

    一、前言

       记录在学习与制作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="20" />
                <ColumnDefinition />
                <ColumnDefinition Width="20" />
                <ColumnDefinition />
                <ColumnDefinition Width="20" />
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <StackPanel Grid.Column="0" Orientation="Horizontal">
                <Label Content="每页显示"/>
                <ComboBox Text="{Binding PagerSize}" 
                Foreground="Orange" VerticalContentAlignment="Center"> <ComboBoxItem Content="10"/> <ComboBoxItem Content="20"/> <ComboBoxItem Content="50"/> </ComboBox> <Label Content=""/> </StackPanel> <StackPanel Grid.Column="2" Orientation="Horizontal"> <Label Content="当前显示数目:"/> <Label Content="{Binding PagerRecord}" Foreground="Orange"/> </StackPanel> <StackPanel Grid.Column="4" Orientation="Horizontal"> <Label Content="查询总量:"/> <Label Content="{Binding PagerQuantity}" Foreground="Orange"/> <Label Content="页,共"/> <Label Content="{Binding TotalRecord}" Foreground="Orange"/> <Label Content=""/> </StackPanel> <StackPanel Grid.Column="6"
                
    Orientation="Horizontal" VerticalAlignment="Center"> <Button Content="首页" Width="40" Height="20"
                Template="{StaticResource DefaultButton}"
                Command="{Binding PagerFirst}"/> <Button Content="上页" Width="60" Height="20"
                Template="{StaticResource DefaultButton}"
                Command="{Binding PagerBefore}" /> <Label Content="{Binding PagerIndex}"
                Foreground="Orange" ToolTip="当前所在页码"/> <Button Content="下页" Width="60"
                Template="{StaticResource DefaultButton}"
                Command="{Binding PagerAfter}" /> <Button Content="末页" Width="40" 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="0" 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="10" Color="#1C86EE"
                    Direction="0" Opacity="0.6"
                    RenderingBias="Performance" ShadowDepth="0" /> </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 = 20;
    
       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 = 1; //第几页
       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 = 1;
            PageChanged?.Invoke(1);
       }
    
       // 上一页事件
       private void PageBefore()
       {
            PagerIndex--;
            if (PagerIndex < 1)
            {
                PagerIndex = 1;
                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 = 1;
            PagerSize = DefaultSize;
            PagerRecord = 0;
            PagerQuantity = 0;
            TotalRecord = 0;
       }
    }

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

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

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

    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 = 0; 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<=0) { result.FullPingYin = items; result.FirstPingYin = items.ConvertAll(
                        p => p.Substring(0, 1))
                        .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(0, 1))); } 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 = 100) { 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, 0, byteData.Length); httpRequest.Timeout = 15000; 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, 3); return JsonConvert.DeserializeObject<T>(strResponse); } public static void TryMultiTime(
          Action act, int tryTimes, int interval = 2000) { var i = 0; 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("主机地址", 25)
          {
             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, 0, 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.下篇预告

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

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

  • 相关阅读:
    GlusterFS-分布式存储集群部署
    keepalived+HAproxy集群部署
    LB-HAproxy负载均衡部署
    Pacemaker高可用环境实践
    Nginx-负载均衡部署
    LB-LVS常见模式NAT/DR部署
    HTTPS原理、应用
    LDAP-autofs挂载用户验证
    GPG-非对称加密
    大数据入门学习(Linux)
  • 原文地址:https://www.cnblogs.com/yjwlogs/p/8467251.html
Copyright © 2020-2023  润新知