工具代碼記錄
版權聲明:本文為博主初學經驗,未經博主允許不得轉載。
一、前言
記錄在學習與制作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.下篇預告
干貨貼代碼,包含需求文案、設計思路、簡要數據庫結構、簡要流程圖和明細代碼,動圖細化每步操作,入門級引導文章;
項目功能包括:登錄、首頁、數據維護 和 全文搜索等增刪查改的常用操作;