更新程序 新界面,显示更新日志

This commit is contained in:
chfei committed 2026-10-13 16:43:57 +08:00
1 parent b0af3bd106
commit 558f9bfa04
6 files changed
+1486 -401

No files matched your search

+562 -270
View File
@@ -1,8 +1,10 @@
using System;
using COSXML.Network;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.IO.Compression;
using System.Linq;
@@ -12,307 +14,597 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using static Update.ChangelogTheme;
namespace Update
{
public partial class MainForm : Form
{
public string Title { get { return Text; } set { Text = value; } }
private Point mouseOffset; // 记录鼠标指针的坐标
private bool isMouseDown; // 记录鼠标左键是否按下
public partial class MainForm : Form
{
public string Title { get { return Text; } set { Text = value; } }
private Point mouseOffset; // 记录鼠标指针的坐标
private bool isMouseDown; // 记录鼠标左键是否按下
public MainForm()
{
InitializeComponent();
public MainForm()
{
InitializeComponent();
this.TopMost = true;
}
this.TopMost = true;
lb_title.Text = "更新日志";
private void MessageForm_Paint(object sender, PaintEventArgs e)
{
SetFormRoundRectRgn(this, 7);
SetFormRoundRectRgn(panel2, 7);
SetFormRoundRectRgn(this.btnOk, 7);
SetFormRoundRectRgn(this.btnCancel, 7);
}
var changelogItems = GetChangeInfos();
if (changelogItems != null)
{
private void btnOk_Click(object sender, EventArgs e)
{
if (lblMessage.Text == "升级完成,点击确定重启程序")
{
string extPath = System.Environment.CurrentDirectory + "\\" + Program.softName.Replace(".exe", "") + ".exe";
System.Diagnostics.Process.Start(extPath);
Application.Exit();
return;
}
string fromVersion = (Program.oldVersion / 100m).ToString();
string toVersion = (Program.newVersion / 100m).ToString();
ShowChangelog(fromVersion, toVersion, changelogItems);
}
btnOk.Enabled = false;
//// 演示数据:v1.0.0 升级到 v1.3.0,展示 1.1.0 ~ 1.3.0(新的在上)
//ShowChangelog("1.0.0", "1.3.0", new[]
//{
// new ChangelogItem { Version = "1.3.0", PublishedAt = "2026-10-10", Notes = "新增深色模式,支持跟随系统\n新增快捷键面板(Ctrl + /)\n启动速度提升 40%" },
// new ChangelogItem { Version = "1.2.0", PublishedAt = "2026-09-05", Notes = "支持导出数据为 Excel 格式\n优化列表滚动性能\n修复偶发的保存失败问题" },
// new ChangelogItem { Version = "1.1.0", PublishedAt = "2026-08-01", Notes = "新增自动更新功能\n修复高分屏下界面模糊的问题" },
//});
}
private List<ChangelogItem> GetChangeInfos()
{
string paidanUrl = $"https://update-wx-order.e57.cn";
string shanghuoUrl = $"https://update.e57.cn";
using (WebClient c = new WebClient())
{
c.Encoding = Encoding.UTF8;
string url = $"/api/releases/since?version={(Program.oldVersion / 100m)}&channel=stable";
if (Program.softName == "29WxFindOrder")
{
url = paidanUrl + url;
}
else if (Program.softName == "29供应链.exe")
url = shanghuoUrl + url;
string json = c.DownloadString(url);
var root = MiniJson.Json.Deserialize(json) as Dictionary<string, object>;
if (root["ok"].ToString() == "True")
{
var data = (Dictionary<string, object>)root["data"];
var versionsRaw = (List<object>)data["versions"];
CloseMainProgram();
var list = new List<ChangelogItem>();
foreach (Dictionary<string, object> item in versionsRaw)
{
var ci = new ChangelogItem
{
Version = item["version"]?.ToString(),
Notes = item["notes"]?.ToString(),
};
if (!System.IO.Directory.Exists("upBak"))
System.IO.Directory.CreateDirectory("upBak");
var upBakPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "upBak";
if (!System.IO.Directory.Exists("upTemp"))
System.IO.Directory.CreateDirectory("upTemp");
var upTempPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "upTemp";
if (DateTime.TryParse(item["publishedAt"]?.ToString(), out DateTime v))
{
ci.PublishedAt = v.ToString("yyyy-MM-dd");
}
list.Add(ci);
}
return list;
}
}
return null;
}
// 清空文件夹准备下载
foreach (string filePath in Directory.GetFiles(upTempPath))
{
File.Delete(filePath); // 删除文件
}
foreach (string dirPath in Directory.GetDirectories(upTempPath))
{
Directory.Delete(dirPath, true); // 删除子文件夹及其内容
}
/// <summary>
/// 渲染更新日志:头部展示版本区间,中间按版本分组列出更新条目
/// </summary>
private void ShowChangelog(string fromVersion, string toVersion, IEnumerable<ChangelogItem> entries)
{
int length = entries.Count();
lblHeroTitle.Text = "v" + fromVersion + " → v" + toVersion;
lblHeroMeta.Text = length > 1 ? "共包含 " + length + " 个版本的更新内容" : "本次更新内容";
this.lblMessage.Text = "升级中请稍候...";
progressBar1.Visible = true;
progressBar1.Maximum = 100;//fileNameArr.Count();
progressBar1.Value = 0;
Task.Run(async() =>
{
string tempFile = upTempPath + "\\" + Program.updateUrl.Substring(Program.updateUrl.LastIndexOf("/") + 1);
//bool result = Program.DownloadFile(Program.updateUrl, tempFile);
panelChangelog.SuspendLayout();
panelChangelog.Controls.Clear();
//while (true)
//{
// Invoke(new Action(() =>
// {
// progressBar1.Value = Program.progress;
// }));
// if (Program.progress == 100)
// break;
//}
var blocks = entries.Select((entry, i) => new ChangelogBlock(entry, i == 0, panelChangelog.Width)).ToList();
int contentHeight = blocks.Sum(b => b.Height);
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
using (var downloadClient = new WebClient())
{
downloadClient.Proxy = null;
// 内容超出可视区时预留垂直滚动条宽度,避免出现横向滚动条
int width = panelChangelog.ClientSize.Width;
if (contentHeight > panelChangelog.ClientSize.Height)
width -= SystemInformation.VerticalScrollBarWidth;
downloadClient.DownloadProgressChanged += (s, args) =>
{
Invoke(new Action(() => { progressBar1.Value = args.ProgressPercentage; }));
};
int y = 6;
foreach (var block in blocks)
{
block.Width = width;
block.Location = new Point(0, y);
y += block.Height;
panelChangelog.Controls.Add(block);
}
panelChangelog.ResumeLayout(true);
}
await downloadClient.DownloadFileTaskAsync(new Uri(Program.updateUrl), tempFile);
}
private void heroPanel_Paint(object sender, PaintEventArgs e)
{
var panel = (Panel)sender;
if (panel.Width <= 0 || panel.Height <= 0)
return;
if (1 == 1)
//if (result)
{
ZipFile.ExtractToDirectory(tempFile, upTempPath);
File.Delete(tempFile);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var brush = new LinearGradientBrush(panel.ClientRectangle, AccentBg, Color.White, 40F))
e.Graphics.FillRectangle(brush, panel.ClientRectangle);
string mainPath = System.Environment.CurrentDirectory;
// 备份旧文件
foreach (string filePath in Directory.GetFiles(upTempPath))
{
try
{
string fileName = filePath.Substring(filePath.LastIndexOf("\\") + 1);
File.Copy(mainPath + "\\" + fileName, upBakPath + "\\" + fileName, true);
Thread.Sleep(10);
}
catch
{
}
}
foreach (string dirPath in Directory.GetDirectories(upTempPath))
{
try
{
string fileName = dirPath.Substring(dirPath.LastIndexOf("\\") + 1);
CopyDirectory(mainPath + "\\" + fileName, upBakPath + "\\" + fileName);
Thread.Sleep(10);
}
catch
{
}
}
using (var pen = new Pen(LineColor))
{
e.Graphics.DrawLine(pen, 0, 0, panel.Width, 0);
e.Graphics.DrawLine(pen, 0, panel.Height - 1, panel.Width, panel.Height - 1);
}
}
string error = "";
// 替换旧文件
foreach (string filePath in Directory.GetFiles(upTempPath))
{
if (!string.IsNullOrEmpty(error))
{
error = "发生错误:\r\n" + error + "\r\n请关闭升级窗口重试!";
break;
}
try
{
string fileName = filePath.Substring(filePath.LastIndexOf("\\") + 1);
File.Copy(upTempPath + "\\" + fileName, mainPath + "\\" + fileName, true);
Thread.Sleep(10);
}
catch (Exception ex)
{
error = "发生错误:\r\n" + ex.Message + "\r\n请关闭升级窗口重试!";
Invoke(new Action(() =>
{
lblMessage.Text = error;
}));
}
}
foreach (string dirPath in Directory.GetDirectories(upTempPath))
{
if (!string.IsNullOrEmpty(error))
break;
try
{
string fileName = dirPath.Substring(dirPath.LastIndexOf("\\") + 1);
CopyDirectory(upTempPath + "\\" + fileName, mainPath + "\\" + fileName);
Thread.Sleep(10);
}
catch (Exception ex)
{
error = "发生错误:\r\n" + ex.Message + "\r\n请关闭升级窗口重试!";
Invoke(new Action(() =>
{
lblMessage.Text = error;
}));
}
}
Thread.Sleep(50);
Invoke(new Action(() =>
{
if (string.IsNullOrEmpty(error))
{
progressBar1.Value = 100;
lblMessage.Text = "升级完成,点击确定重启程序";
btnOk.Enabled = true;
}
}));
}
else
{
Invoke(new Action(() =>
{
progressBar1.Value = 100;
this.lblMessage.Text = "升级失败,未获取到升级文件";
btnOk.Enabled = true;
}));
}
});
}
private void btnOk_Click(object sender, EventArgs e)
{
if (lblMessage.Text == "升级完成,点击确定重启程序")
{
string extPath = System.Environment.CurrentDirectory + "\\" + Program.softName.Replace(".exe", "") + ".exe";
System.Diagnostics.Process.Start(extPath);
Application.Exit();
return;
}
/// <summary>
/// 拷贝文档目录
/// </summary>
/// <param name="srcPath"></param>
/// <param name="destPath"></param>
public static void CopyDirectory(string srcPath, string destPath)
{
try
{
DirectoryInfo dir = new DirectoryInfo(srcPath);
FileSystemInfo[] fileinfo = dir.GetFileSystemInfos(); //获取目录下(不包含子目录)的文件和子目录
foreach (FileSystemInfo i in fileinfo)
{
if (i is DirectoryInfo) //判断是否文件夹
{
if (!Directory.Exists(destPath + "\\" + i.Name))
{
Directory.CreateDirectory(destPath + "\\" + i.Name); //目标目录下不存在此文件夹即创建子文件夹
}
CopyDirectory(i.FullName, destPath + "\\" + i.Name); //递归调用复制子文件夹
}
else
{
File.Copy(i.FullName, destPath + "\\" + i.Name, true); //不是文件夹即复制文件,true表示可以覆盖同名文件
}
}
}
catch (Exception e)
{
throw;
}
}
btnOk.Enabled = false;
private void btnCancel_Click(object sender, EventArgs e)
{
this.Close();
}
CloseMainProgram();
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
mouseOffset = new Point(-e.X, -e.Y);
isMouseDown = true;
}
}
if (!System.IO.Directory.Exists("upBak"))
System.IO.Directory.CreateDirectory("upBak");
var upBakPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "upBak";
if (!System.IO.Directory.Exists("upTemp"))
System.IO.Directory.CreateDirectory("upTemp");
var upTempPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "upTemp";
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
isMouseDown = false;
}
// 清空文件夹准备下载
foreach (string filePath in Directory.GetFiles(upTempPath))
{
File.Delete(filePath); // 删除文件
}
foreach (string dirPath in Directory.GetDirectories(upTempPath))
{
Directory.Delete(dirPath, true); // 删除子文件夹及其内容
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (isMouseDown)
{
// 获取鼠标的位置
Point mousePos = MousePosition;
mousePos.Offset(mouseOffset.X, mouseOffset.Y);
Location = mousePos;
}
}
this.lblMessage.Text = "升级中请稍候...";
progressBar1.Visible = true;
progressBar1.Maximum = 100;//fileNameArr.Count();
progressBar1.Value = 0;
Task.Run(async () =>
{
string tempFile = upTempPath + "\\" + Program.updateUrl.Substring(Program.updateUrl.LastIndexOf("/") + 1);
//bool result = Program.DownloadFile(Program.updateUrl, tempFile);
public static void SetFormRoundRectRgn(Control c, int rgnRadius)
{
int hRgn = 0;
hRgn = Win32.CreateRoundRectRgn(0, 0, c.Width + 1, c.Height + 1, rgnRadius, rgnRadius);
Win32.SetWindowRgn(c.Handle, hRgn, true);
Win32.DeleteObject(hRgn);
}
//while (true)
//{
// Invoke(new Action(() =>
// {
// progressBar1.Value = Program.progress;
// }));
// if (Program.progress == 100)
// break;
//}
private void btnClose_Click(object sender, EventArgs e)
{
Application.Exit();
}
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
using (var downloadClient = new WebClient())
{
downloadClient.Proxy = null;
private void CloseMainProgram()
{
string in_sAppName = Program.softName; //(一个word文档程序)
in_sAppName = in_sAppName.Replace(".exe", "");
downloadClient.DownloadProgressChanged += (s, args) =>
{
Invoke(new Action(() => { progressBar1.Value = args.ProgressPercentage; }));
try
{
System.Diagnostics.Process[] psiNewcas = System.Diagnostics.Process.GetProcessesByName(in_sAppName);
//System.Diagnostics.Process.GetProcessesByName("");
};
//var pro = System.Diagnostics.Process.GetProcesses();
//foreach(var p in pro)
//{
// Console.WriteLine(p.ProcessName);
//}
await downloadClient.DownloadFileTaskAsync(new Uri(Program.updateUrl), tempFile);
}
foreach (System.Diagnostics.Process p in psiNewcas)
{
p.Kill();
//p.WaitForExit();
//p.Close();
//Console.WriteLine(in_sAppName + "已经停止了");
}
}
catch
{
Console.WriteLine(in_sAppName + "停止失败");
}
}
}
if (1 == 1)
//if (result)
{
ZipFile.ExtractToDirectory(tempFile, upTempPath);
File.Delete(tempFile);
public enum FormLevel
{
SMALL,
MEDIUM,
LARGE = 500
}
string mainPath = System.Environment.CurrentDirectory;
// 备份旧文件
foreach (string filePath in Directory.GetFiles(upTempPath))
{
try
{
string fileName = filePath.Substring(filePath.LastIndexOf("\\") + 1);
File.Copy(mainPath + "\\" + fileName, upBakPath + "\\" + fileName, true);
Thread.Sleep(10);
}
catch
{
}
}
foreach (string dirPath in Directory.GetDirectories(upTempPath))
{
try
{
string fileName = dirPath.Substring(dirPath.LastIndexOf("\\") + 1);
CopyDirectory(mainPath + "\\" + fileName, upBakPath + "\\" + fileName);
Thread.Sleep(10);
}
catch
{
}
}
string error = "";
// 替换旧文件
foreach (string filePath in Directory.GetFiles(upTempPath))
{
if (!string.IsNullOrEmpty(error))
{
error = "发生错误:\r\n" + error + "\r\n请关闭升级窗口重试!";
break;
}
try
{
string fileName = filePath.Substring(filePath.LastIndexOf("\\") + 1);
File.Copy(upTempPath + "\\" + fileName, mainPath + "\\" + fileName, true);
Thread.Sleep(10);
}
catch (Exception ex)
{
error = "发生错误:\r\n" + ex.Message + "\r\n请关闭升级窗口重试!";
Invoke(new Action(() =>
{
lblMessage.Text = error;
}));
}
}
foreach (string dirPath in Directory.GetDirectories(upTempPath))
{
if (!string.IsNullOrEmpty(error))
break;
try
{
string fileName = dirPath.Substring(dirPath.LastIndexOf("\\") + 1);
CopyDirectory(upTempPath + "\\" + fileName, mainPath + "\\" + fileName);
Thread.Sleep(10);
}
catch (Exception ex)
{
error = "发生错误:\r\n" + ex.Message + "\r\n请关闭升级窗口重试!";
Invoke(new Action(() =>
{
lblMessage.Text = error;
}));
}
}
Thread.Sleep(50);
Invoke(new Action(() =>
{
if (string.IsNullOrEmpty(error))
{
progressBar1.Value = 100;
lblMessage.Text = "升级完成,点击确定重启程序";
btnOk.Enabled = true;
}
}));
}
else
{
Invoke(new Action(() =>
{
progressBar1.Value = 100;
this.lblMessage.Text = "升级失败,未获取到升级文件";
btnOk.Enabled = true;
}));
}
});
}
/// <summary>
/// 拷贝文档目录
/// </summary>
/// <param name="srcPath"></param>
/// <param name="destPath"></param>
public static void CopyDirectory(string srcPath, string destPath)
{
try
{
DirectoryInfo dir = new DirectoryInfo(srcPath);
FileSystemInfo[] fileinfo = dir.GetFileSystemInfos(); //获取目录下(不包含子目录)的文件和子目录
foreach (FileSystemInfo i in fileinfo)
{
if (i is DirectoryInfo) //判断是否文件夹
{
if (!Directory.Exists(destPath + "\\" + i.Name))
{
Directory.CreateDirectory(destPath + "\\" + i.Name); //目标目录下不存在此文件夹即创建子文件夹
}
CopyDirectory(i.FullName, destPath + "\\" + i.Name); //递归调用复制子文件夹
}
else
{
File.Copy(i.FullName, destPath + "\\" + i.Name, true); //不是文件夹即复制文件,true表示可以覆盖同名文件
}
}
}
catch (Exception e)
{
throw;
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
this.Close();
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
mouseOffset = new Point(-e.X, -e.Y);
isMouseDown = true;
}
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
isMouseDown = false;
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (isMouseDown)
{
// 获取鼠标的位置
Point mousePos = MousePosition;
mousePos.Offset(mouseOffset.X, mouseOffset.Y);
Location = mousePos;
}
}
private void btnClose_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void CloseMainProgram()
{
string in_sAppName = Program.softName; //(一个word文档程序)
in_sAppName = in_sAppName.Replace(".exe", "");
try
{
System.Diagnostics.Process[] psiNewcas = System.Diagnostics.Process.GetProcessesByName(in_sAppName);
//System.Diagnostics.Process.GetProcessesByName("");
//var pro = System.Diagnostics.Process.GetProcesses();
//foreach(var p in pro)
//{
// Console.WriteLine(p.ProcessName);
//}
foreach (System.Diagnostics.Process p in psiNewcas)
{
p.Kill();
//p.WaitForExit();
//p.Close();
//Console.WriteLine(in_sAppName + "已经停止了");
}
}
catch
{
Console.WriteLine(in_sAppName + "停止失败");
}
}
private void panel2_Paint(object sender, PaintEventArgs e)
{
}
}
public class Changelog
{
public bool Ok { get; set; }
public ChangelogData Data { get; set; }
}
public class ChangelogData
{
public List<ChangelogItem> versions { get; set; }
}
/// <summary>
/// 单个版本的更新日志
/// </summary>
public class ChangelogItem
{
public string Version { get; set; }
public string PublishedAt { get; set; }
public string Notes { get; set; }
public string[] Items
{
get
{
string[] temp = new string[0];
if (string.IsNullOrEmpty(Notes)) return temp;
return Notes.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
}
}
}
/// <summary>
/// 更新日志中的单个版本区块:版本标题行(色条 + 版本号 + 最新标记 + 日期)与条目列表
/// </summary>
public class ChangelogBlock : Panel
{
private const int LeftPad = 28;
private const int RightPad = 28;
private const int BarWidth = 3;
private const int BarHeight = 16;
private const int TextLeft = 55; // 条目文字左边,留出圆点位置
private const int ItemPadding = 5; // 条目上下内边距
private const int BottomGap = 20; // 区块底部留白
private const int HeaderHeight = 28;
private readonly bool isNewest;
private readonly Font versionFont = new Font("微软雅黑", 12F, FontStyle.Bold);
private readonly Font dateFont = new Font("微软雅黑", 9F);
private readonly Font badgeFont = new Font("微软雅黑", 8.5F);
private readonly Font itemFont = new Font("微软雅黑", 10.5F);
private readonly Size versionSize;
private readonly Size dateSize;
private readonly List<System.Windows.Forms.Label> lblItems = new List<System.Windows.Forms.Label>();
private readonly System.Windows.Forms.Label lblVersion = new System.Windows.Forms.Label();
private readonly System.Windows.Forms.Label lblDate = new System.Windows.Forms.Label();
private Rectangle badgeRect = Rectangle.Empty;
private Rectangle barRect = Rectangle.Empty;
private readonly List<Point> bulletPoints = new List<Point>();
private int laidOutWidth = -1;
public ChangelogBlock(ChangelogItem entry, bool isNewest, int width)
{
this.isNewest = isNewest;
BackColor = Color.White;
DoubleBuffered = true;
versionSize = TextRenderer.MeasureText("v" + entry.Version, versionFont);
dateSize = TextRenderer.MeasureText(entry.PublishedAt, dateFont);
lblVersion.Font = versionFont;
lblVersion.ForeColor = Accent;
lblVersion.BackColor = Color.White;
lblVersion.Text = "v" + entry.Version;
Controls.Add(lblVersion);
lblDate.Font = dateFont;
lblDate.ForeColor = SubColor;
lblDate.BackColor = Color.White;
lblDate.Text = entry.PublishedAt;
Controls.Add(lblDate);
foreach (string item in entry.Items)
{
var label = new System.Windows.Forms.Label
{
Font = itemFont,
ForeColor = TextColor,
BackColor = Color.White,
Padding = new Padding(0, ItemPadding, 0, ItemPadding),
Text = item
};
lblItems.Add(label);
Controls.Add(label);
}
Width = width;
}
protected override void OnResize(EventArgs eventargs)
{
base.OnResize(eventargs);
LayoutContent(Width);
}
private void LayoutContent(int width)
{
if (width <= 0 || width == laidOutWidth)
return;
laidOutWidth = width;
SuspendLayout();
barRect = new Rectangle(LeftPad, (HeaderHeight - BarHeight) / 2, BarWidth, BarHeight);
lblVersion.SetBounds(LeftPad + BarWidth + 8, (HeaderHeight - versionSize.Height) / 2, versionSize.Width, versionSize.Height);
badgeRect = Rectangle.Empty;
int headerRight = lblVersion.Right;
if (isNewest)
{
Size badgeSize = TextRenderer.MeasureText("最新", badgeFont, Size.Empty, TextFormatFlags.NoPadding);
badgeRect = new Rectangle(headerRight + 8, (HeaderHeight - 18) / 2, badgeSize.Width + 16, 18);
headerRight = badgeRect.Right;
}
lblDate.SetBounds(Math.Max(headerRight + 8, width - RightPad - dateSize.Width),
(HeaderHeight - dateSize.Height) / 2, dateSize.Width, dateSize.Height);
int lineHeight = TextRenderer.MeasureText("中", itemFont, Size.Empty, TextFormatFlags.NoPadding).Height;
int textWidth = Math.Max(60, width - TextLeft - RightPad);
bulletPoints.Clear();
int y = HeaderHeight;
foreach (var label in lblItems)
{
int measured = TextRenderer.MeasureText(label.Text, itemFont, new Size(textWidth, 0), TextFormatFlags.WordBreak).Height;
label.SetBounds(TextLeft, y, textWidth, measured + ItemPadding * 2);
bulletPoints.Add(new Point(TextLeft - 14, y + ItemPadding + lineHeight / 2));
y += label.Height;
}
Height = y + BottomGap;
ResumeLayout(false);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
using (var path = RoundedRect(barRect, BarWidth / 2f))
using (var brush = new SolidBrush(Accent))
g.FillPath(brush, path);
if (isNewest && badgeRect.Width > 0)
{
using (var path = RoundedRect(badgeRect, badgeRect.Height / 2f))
using (var brush = new SolidBrush(Accent))
g.FillPath(brush, path);
TextRenderer.DrawText(g, "最新", badgeFont, badgeRect, Color.White,
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.NoPadding);
}
using (var dot = new SolidBrush(Accent))
foreach (Point p in bulletPoints)
g.FillEllipse(dot, p.X - 3, p.Y - 3, 6, 6);
}
private static GraphicsPath RoundedRect(Rectangle rect, float radius)
{
var path = new GraphicsPath();
float d = radius * 2;
path.AddArc(rect.X, rect.Y, d, d, 180, 90);
path.AddArc(rect.Right - d, rect.Y, d, d, 270, 90);
path.AddArc(rect.Right - d, rect.Bottom - d, d, d, 0, 90);
path.AddArc(rect.X, rect.Bottom - d, d, d, 90, 90);
path.CloseFigure();
return path;
}
}
public enum FormLevel
{
SMALL,
MEDIUM,
LARGE = 500
}
/// <summary>
/// 更新日志窗口的配色,与设计稿保持一致
/// </summary>
internal static class ChangelogTheme
{
public static readonly Color Accent = Color.FromArgb(152, 99, 143);
public static readonly Color AccentBg = Color.FromArgb(245, 237, 244);
public static readonly Color SubColor = Color.FromArgb(107, 114, 128);
public static readonly Color LineColor = Color.FromArgb(229, 231, 238);
public static readonly Color TextColor = Color.FromArgb(31, 36, 48);
}
}
+216 -128
View File
@@ -29,135 +29,217 @@ namespace Update
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
this.lblMessage = new System.Windows.Forms.Label();
this.btnOk = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.panel1 = new System.Windows.Forms.Panel();
this.btnClose = new System.Windows.Forms.Button();
this.panel2 = new System.Windows.Forms.Panel();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.panel1.SuspendLayout();
this.panel2.SuspendLayout();
this.SuspendLayout();
//
// lblMessage
//
this.lblMessage.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
this.lblMessage = new System.Windows.Forms.Label();
this.btnOk = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.panel1 = new System.Windows.Forms.Panel();
this.lb_title = new System.Windows.Forms.Label();
this.btnClose = new System.Windows.Forms.Button();
this.panel2 = new System.Windows.Forms.Panel();
this.heroPanel = new System.Windows.Forms.Panel();
this.lblHeroTitle = new System.Windows.Forms.Label();
this.lblHeroMeta = new System.Windows.Forms.Label();
this.panelChangelog = new System.Windows.Forms.Panel();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.panel3 = new System.Windows.Forms.Panel();
this.panel1.SuspendLayout();
this.panel2.SuspendLayout();
this.heroPanel.SuspendLayout();
this.SuspendLayout();
//
// lblMessage
//
this.lblMessage.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.lblMessage.Location = new System.Drawing.Point(14, 33);
this.lblMessage.Name = "lblMessage";
this.lblMessage.Size = new System.Drawing.Size(327, 98);
this.lblMessage.TabIndex = 0;
this.lblMessage.Text = "发现新版本,即将为您升级!";
this.lblMessage.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// btnOk
//
this.btnOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnOk.BackColor = System.Drawing.Color.Blue;
this.btnOk.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnOk.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(255)))));
this.btnOk.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnOk.Font = new System.Drawing.Font("微软雅黑", 11F);
this.btnOk.ForeColor = System.Drawing.Color.White;
this.btnOk.Location = new System.Drawing.Point(232, 177);
this.btnOk.Name = "btnOk";
this.btnOk.Size = new System.Drawing.Size(109, 30);
this.btnOk.TabIndex = 9;
this.btnOk.TabStop = false;
this.btnOk.Text = "确 定";
this.btnOk.UseVisualStyleBackColor = false;
this.btnOk.Click += new System.EventHandler(this.btnOk_Click);
//
// btnCancel
//
this.btnCancel.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnCancel.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(255)))));
this.btnCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnCancel.Font = new System.Drawing.Font("微软雅黑", 11F);
this.btnCancel.ForeColor = System.Drawing.Color.Blue;
this.btnCancel.Location = new System.Drawing.Point(14, 177);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(109, 30);
this.btnCancel.TabIndex = 10;
this.btnCancel.TabStop = false;
this.btnCancel.Text = "取 消";
this.btnCancel.UseVisualStyleBackColor = false;
this.btnCancel.Visible = false;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// panel1
//
this.panel1.BackColor = System.Drawing.Color.Blue;
this.panel1.Controls.Add(this.btnClose);
this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
this.panel1.Location = new System.Drawing.Point(2, 2);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(355, 24);
this.panel1.TabIndex = 11;
this.panel1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseDown);
this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseMove);
this.panel1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseUp);
//
// btnClose
//
this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnClose.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnClose.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(255)))));
this.btnClose.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnClose.Font = new System.Drawing.Font("微软雅黑", 11F);
this.btnClose.ForeColor = System.Drawing.Color.White;
this.btnClose.Location = new System.Drawing.Point(339, -5);
this.btnClose.Name = "btnClose";
this.btnClose.Size = new System.Drawing.Size(17, 28);
this.btnClose.TabIndex = 11;
this.btnClose.TabStop = false;
this.btnClose.Text = "x";
this.btnClose.UseVisualStyleBackColor = false;
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
//
// panel2
//
this.panel2.BackColor = System.Drawing.Color.White;
this.panel2.Controls.Add(this.progressBar1);
this.panel2.Controls.Add(this.lblMessage);
this.panel2.Controls.Add(this.btnOk);
this.panel2.Controls.Add(this.btnCancel);
this.panel2.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel2.Location = new System.Drawing.Point(2, 2);
this.panel2.Name = "panel2";
this.panel2.Size = new System.Drawing.Size(355, 221);
this.panel2.TabIndex = 12;
//
// progressBar1
//
this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
this.lblMessage.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(107)))), ((int)(((byte)(114)))), ((int)(((byte)(128)))));
this.lblMessage.Location = new System.Drawing.Point(20, 416);
this.lblMessage.Name = "lblMessage";
this.lblMessage.Size = new System.Drawing.Size(607, 45);
this.lblMessage.TabIndex = 0;
this.lblMessage.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
// btnOk
//
this.btnOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnOk.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(152)))), ((int)(((byte)(99)))), ((int)(((byte)(143)))));
this.btnOk.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnOk.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(152)))), ((int)(((byte)(99)))), ((int)(((byte)(143)))));
this.btnOk.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnOk.Font = new System.Drawing.Font("微软雅黑", 11F);
this.btnOk.ForeColor = System.Drawing.Color.White;
this.btnOk.Location = new System.Drawing.Point(522, 521);
this.btnOk.Name = "btnOk";
this.btnOk.Size = new System.Drawing.Size(109, 30);
this.btnOk.TabIndex = 9;
this.btnOk.TabStop = false;
this.btnOk.Text = "确 定";
this.btnOk.UseVisualStyleBackColor = false;
this.btnOk.Click += new System.EventHandler(this.btnOk_Click);
//
// btnCancel
//
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnCancel.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnCancel.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(152)))), ((int)(((byte)(99)))), ((int)(((byte)(143)))));
this.btnCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnCancel.Font = new System.Drawing.Font("微软雅黑", 11F);
this.btnCancel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(152)))), ((int)(((byte)(99)))), ((int)(((byte)(143)))));
this.btnCancel.Location = new System.Drawing.Point(24, 521);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(109, 30);
this.btnCancel.TabIndex = 10;
this.btnCancel.TabStop = false;
this.btnCancel.Text = "取 消";
this.btnCancel.UseVisualStyleBackColor = false;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// panel1
//
this.panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(152)))), ((int)(((byte)(99)))), ((int)(((byte)(143)))));
this.panel1.Controls.Add(this.lb_title);
this.panel1.Controls.Add(this.btnClose);
this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
this.panel1.Location = new System.Drawing.Point(2, 2);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(663, 24);
this.panel1.TabIndex = 11;
this.panel1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseDown);
this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseMove);
this.panel1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseUp);
//
// lb_title
//
this.lb_title.AutoSize = true;
this.lb_title.ForeColor = System.Drawing.Color.White;
this.lb_title.Location = new System.Drawing.Point(3, 1);
this.lb_title.Name = "lb_title";
this.lb_title.Size = new System.Drawing.Size(50, 20);
this.lb_title.TabIndex = 12;
this.lb_title.Text = "label1";
//
// btnClose
//
this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnClose.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnClose.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(152)))), ((int)(((byte)(99)))), ((int)(((byte)(143)))));
this.btnClose.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnClose.Font = new System.Drawing.Font("微软雅黑", 13F);
this.btnClose.ForeColor = System.Drawing.Color.White;
this.btnClose.Location = new System.Drawing.Point(629, -6);
this.btnClose.Margin = new System.Windows.Forms.Padding(0);
this.btnClose.Name = "btnClose";
this.btnClose.Size = new System.Drawing.Size(35, 35);
this.btnClose.TabIndex = 11;
this.btnClose.TabStop = false;
this.btnClose.Text = "✕";
this.btnClose.UseVisualStyleBackColor = false;
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
//
// panel2
//
this.panel2.BackColor = System.Drawing.Color.White;
this.panel2.Controls.Add(this.panel3);
this.panel2.Controls.Add(this.heroPanel);
this.panel2.Controls.Add(this.panelChangelog);
this.panel2.Controls.Add(this.progressBar1);
this.panel2.Controls.Add(this.lblMessage);
this.panel2.Controls.Add(this.btnOk);
this.panel2.Controls.Add(this.btnCancel);
this.panel2.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel2.Location = new System.Drawing.Point(2, 2);
this.panel2.Name = "panel2";
this.panel2.Size = new System.Drawing.Size(663, 583);
this.panel2.TabIndex = 12;
this.panel2.Paint += new System.Windows.Forms.PaintEventHandler(this.panel2_Paint);
//
// heroPanel
//
this.heroPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.progressBar1.Location = new System.Drawing.Point(14, 139);
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(327, 23);
this.progressBar1.TabIndex = 11;
this.progressBar1.Visible = false;
//
// MainForm
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(255)))));
this.ClientSize = new System.Drawing.Size(359, 225);
this.Controls.Add(this.panel1);
this.Controls.Add(this.panel2);
this.Font = new System.Drawing.Font("微软雅黑", 10F);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "MainForm";
this.Padding = new System.Windows.Forms.Padding(2);
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "MessageForm";
this.Paint += new System.Windows.Forms.PaintEventHandler(this.MessageForm_Paint);
this.panel1.ResumeLayout(false);
this.panel2.ResumeLayout(false);
this.ResumeLayout(false);
this.heroPanel.Controls.Add(this.lblHeroTitle);
this.heroPanel.Controls.Add(this.lblHeroMeta);
this.heroPanel.Location = new System.Drawing.Point(0, 24);
this.heroPanel.Name = "heroPanel";
this.heroPanel.Size = new System.Drawing.Size(663, 92);
this.heroPanel.TabIndex = 13;
this.heroPanel.Paint += new System.Windows.Forms.PaintEventHandler(this.heroPanel_Paint);
//
// lblHeroTitle
//
this.lblHeroTitle.AutoSize = true;
this.lblHeroTitle.BackColor = System.Drawing.Color.Transparent;
this.lblHeroTitle.Font = new System.Drawing.Font("微软雅黑", 16F, System.Drawing.FontStyle.Bold);
this.lblHeroTitle.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(152)))), ((int)(((byte)(99)))), ((int)(((byte)(143)))));
this.lblHeroTitle.Location = new System.Drawing.Point(28, 18);
this.lblHeroTitle.Name = "lblHeroTitle";
this.lblHeroTitle.Size = new System.Drawing.Size(183, 30);
this.lblHeroTitle.TabIndex = 0;
this.lblHeroTitle.Text = "v1.0.0 → v1.3.0";
//
// lblHeroMeta
//
this.lblHeroMeta.AutoSize = true;
this.lblHeroMeta.BackColor = System.Drawing.Color.Transparent;
this.lblHeroMeta.Font = new System.Drawing.Font("微软雅黑", 9F);
this.lblHeroMeta.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(107)))), ((int)(((byte)(114)))), ((int)(((byte)(128)))));
this.lblHeroMeta.Location = new System.Drawing.Point(30, 58);
this.lblHeroMeta.Name = "lblHeroMeta";
this.lblHeroMeta.Size = new System.Drawing.Size(155, 17);
this.lblHeroMeta.TabIndex = 1;
this.lblHeroMeta.Text = "共包含 3 个版本的更新内容";
//
// panelChangelog
//
this.panelChangelog.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panelChangelog.AutoScroll = true;
this.panelChangelog.BackColor = System.Drawing.Color.White;
this.panelChangelog.Location = new System.Drawing.Point(0, 116);
this.panelChangelog.Name = "panelChangelog";
this.panelChangelog.Size = new System.Drawing.Size(663, 291);
this.panelChangelog.TabIndex = 14;
//
// progressBar1
//
this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.progressBar1.Location = new System.Drawing.Point(24, 468);
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(607, 16);
this.progressBar1.TabIndex = 11;
this.progressBar1.Visible = false;
//
// panel3
//
this.panel3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(229)))), ((int)(((byte)(231)))), ((int)(((byte)(238)))));
this.panel3.Location = new System.Drawing.Point(0, 496);
this.panel3.Margin = new System.Windows.Forms.Padding(1);
this.panel3.Name = "panel3";
this.panel3.Size = new System.Drawing.Size(664, 1);
this.panel3.TabIndex = 15;
//
// MainForm
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(152)))), ((int)(((byte)(99)))), ((int)(((byte)(143)))));
this.ClientSize = new System.Drawing.Size(667, 587);
this.Controls.Add(this.panel1);
this.Controls.Add(this.panel2);
this.Font = new System.Drawing.Font("微软雅黑", 10F);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "MainForm";
this.Padding = new System.Windows.Forms.Padding(2);
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "MessageForm";
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.panel2.ResumeLayout(false);
this.heroPanel.ResumeLayout(false);
this.heroPanel.PerformLayout();
this.ResumeLayout(false);
}
@@ -170,5 +252,11 @@ namespace Update
private System.Windows.Forms.Panel panel2;
private System.Windows.Forms.Button btnClose;
private System.Windows.Forms.ProgressBar progressBar1;
}
private System.Windows.Forms.Panel heroPanel;
private System.Windows.Forms.Label lblHeroTitle;
private System.Windows.Forms.Label lblHeroMeta;
private System.Windows.Forms.Panel panelChangelog;
private System.Windows.Forms.Label lb_title;
private System.Windows.Forms.Panel panel3;
}
}
+699
View File
@@ -0,0 +1,699 @@
/*
* Copyright (c) 2013 Calvin Rien
*
* Based on the JSON parser by Patrick van Bergen
* http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html
*
* Simplified it so that it doesn't throw exceptions
* and can be used in Unity iPhone with maximum code stripping.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
namespace MiniJson
{
// Example usage:
//
// using UnityEngine;
// using System.Collections;
// using System.Collections.Generic;
// using MiniJSON;
//
// public class MiniJSONTest : MonoBehaviour {
// void Start () {
// var jsonString = "{ \"array\": [1.44,2,3], " +
// "\"object\": {\"key1\":\"value1\", \"key2\":256}, " +
// "\"string\": \"The quick brown fox \\\"jumps\\\" over the lazy dog \", " +
// "\"unicode\": \"\\u3041 Men\u00fa sesi\u00f3n\", " +
// "\"int\": 65536, " +
// "\"float\": 3.1415926, " +
// "\"bool\": true, " +
// "\"null\": null }";
//
// var dict = Json.Deserialize(jsonString) as Dictionary<string,object>;
//
// Debug.Log("deserialized: " + dict.GetType());
// Debug.Log("dict['array'][0]: " + ((List<object>) dict["array"])[0]);
// Debug.Log("dict['string']: " + (string) dict["string"]);
// Debug.Log("dict['float']: " + (double) dict["float"]); // floats come out as doubles
// Debug.Log("dict['int']: " + (long) dict["int"]); // ints come out as longs
// Debug.Log("dict['unicode']: " + (string) dict["unicode"]);
//
// var str = Json.Serialize(dict);
//
// Debug.Log("serialized: " + str);
// }
// }
/// <summary>
/// This class encodes and decodes JSON strings.
/// Spec. details, see http://www.json.org/
///
/// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary.
/// All numbers are parsed to doubles.
/// </summary>
public static class Json
{
/// <summary>
/// Parses the string json into a value
/// </summary>
/// <param name="json">A JSON string.</param>
/// <returns>An List&lt;object&gt;, a Dictionary&lt;string, object&gt;, a double, an integer,a string, null, true, or false</returns>
public static object Deserialize(string json)
{
// save the string for debug information
if (json == null)
{
return null;
}
return Parser.Parse(json);
}
public static T Deserialize<T>(string json)
where T:class,new()
{
T model =new T();
Dictionary<string,object> dic=Deserialize(json) as Dictionary<string,object>;
if (dic != null)
{
var properties = model.GetType().GetProperties();
foreach (var pro in properties)
{
if (dic.ContainsKey(pro.Name))
{
object val;
if (dic[pro.Name]==null && pro.PropertyType.IsValueType)
{
val = null;
}
else
{
val = Convert.ChangeType(dic[pro.Name], pro.PropertyType);
}
pro.SetValue(model, val,null);
}
}
}
return model;
}
/// <summary>
/// Converts a Dictionary / List object or a simple type or a class type (string, int, etc.) into a JSON string
/// </summary>
/// <param name="obj">A Dictionary&lt;string, object&gt; / List&lt;object&gt;</param>
/// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns>
//public static string Serialize(object obj)
//{
// return Serializer.Serialize(obj);
//}
public static string Serialize(object obj)
{
if (obj.GetType() == typeof(Dictionary<string, object>) || obj.GetType() == typeof(List<object>))
{
return Serializer.Serialize(obj);
}
else if (obj.GetType().IsClass)
{
var properties = obj.GetType().GetProperties();
Dictionary<string, object> dic = new Dictionary<string, object>();
foreach (var pro in properties)
{
dic.Add(pro.Name, pro.GetValue(obj, null));
}
return Serializer.Serialize(dic);
}
else
return null;
}
sealed class Parser : IDisposable
{
const string WORD_BREAK = "{}[],:\"";
public static bool IsWordBreak(char c)
{
return Char.IsWhiteSpace(c) || WORD_BREAK.IndexOf(c) != -1;
}
const string HEX_DIGIT = "0123456789ABCDEFabcdef";
public static bool IsHexDigit(char c)
{
return HEX_DIGIT.IndexOf(c) != -1;
}
enum TOKEN
{
NONE,
CURLY_OPEN,
CURLY_CLOSE,
SQUARED_OPEN,
SQUARED_CLOSE,
COLON,
COMMA,
STRING,
NUMBER,
TRUE,
FALSE,
NULL
};
StringReader json;
Parser(string jsonString)
{
json = new StringReader(jsonString);
}
public static object Parse(string jsonString)
{
using (var instance = new Parser(jsonString))
{
return instance.ParseValue();
}
}
public void Dispose()
{
json.Dispose();
json = null;
}
Dictionary<string, object> ParseObject()
{
Dictionary<string, object> table = new Dictionary<string, object>();
// ditch opening brace
json.Read();
// {
while (true)
{
switch (NextToken)
{
case TOKEN.NONE:
return null;
case TOKEN.COMMA:
continue;
case TOKEN.CURLY_CLOSE:
return table;
case TOKEN.STRING:
// name
string name = ParseString();
if (name == null)
{
return null;
}
// :
if (NextToken != TOKEN.COLON)
{
return null;
}
// ditch the colon
json.Read();
// value
TOKEN valueToken = NextToken;
object value = ParseByToken(valueToken);
if (value == null && valueToken != TOKEN.NULL)
return null;
table[name] = value;
break;
default:
return null;
}
}
}
List<object> ParseArray()
{
List<object> array = new List<object>();
// ditch opening bracket
json.Read();
// [
var parsing = true;
while (parsing)
{
TOKEN nextToken = NextToken;
switch (nextToken)
{
case TOKEN.NONE:
return null;
case TOKEN.COMMA:
continue;
case TOKEN.SQUARED_CLOSE:
parsing = false;
break;
default:
object value = ParseByToken(nextToken);
if (value == null && nextToken != TOKEN.NULL)
return null;
array.Add(value);
break;
}
}
return array;
}
object ParseValue()
{
TOKEN nextToken = NextToken;
return ParseByToken(nextToken);
}
object ParseByToken(TOKEN token)
{
switch (token)
{
case TOKEN.STRING:
return ParseString();
case TOKEN.NUMBER:
return ParseNumber();
case TOKEN.CURLY_OPEN:
return ParseObject();
case TOKEN.SQUARED_OPEN:
return ParseArray();
case TOKEN.TRUE:
return true;
case TOKEN.FALSE:
return false;
case TOKEN.NULL:
return null;
default:
return null;
}
}
string ParseString()
{
StringBuilder s = new StringBuilder();
char c;
// ditch opening quote
json.Read();
bool parsing = true;
while (parsing)
{
if (json.Peek() == -1)
{
parsing = false;
break;
}
c = NextChar;
switch (c)
{
case '"':
parsing = false;
break;
case '\\':
if (json.Peek() == -1)
{
parsing = false;
break;
}
c = NextChar;
switch (c)
{
case '"':
case '\\':
case '/':
s.Append(c);
break;
case 'b':
s.Append('\b');
break;
case 'f':
s.Append('\f');
break;
case 'n':
s.Append('\n');
break;
case 'r':
s.Append('\r');
break;
case 't':
s.Append('\t');
break;
case 'u':
var hex = new char[4];
for (int i = 0; i < 4; i++)
{
hex[i] = NextChar;
if (!IsHexDigit(hex[i]))
return null;
}
s.Append((char)Convert.ToInt32(new string(hex), 16));
break;
}
break;
default:
s.Append(c);
break;
}
}
return s.ToString();
}
object ParseNumber()
{
string number = NextWord;
if (number.IndexOf('.') == -1 && number.IndexOf('E') == -1 && number.IndexOf('e') == -1)
{
long parsedInt;
Int64.TryParse(number, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out parsedInt);
return parsedInt;
}
double parsedDouble;
Double.TryParse(number, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out parsedDouble);
return parsedDouble;
}
void EatWhitespace()
{
while (Char.IsWhiteSpace(PeekChar))
{
json.Read();
if (json.Peek() == -1)
{
break;
}
}
}
char PeekChar
{
get
{
return Convert.ToChar(json.Peek());
}
}
char NextChar
{
get
{
return Convert.ToChar(json.Read());
}
}
string NextWord
{
get
{
StringBuilder word = new StringBuilder();
while (!IsWordBreak(PeekChar))
{
word.Append(NextChar);
if (json.Peek() == -1)
{
break;
}
}
return word.ToString();
}
}
TOKEN NextToken
{
get
{
EatWhitespace();
if (json.Peek() == -1)
{
return TOKEN.NONE;
}
switch (PeekChar)
{
case '{':
return TOKEN.CURLY_OPEN;
case '}':
json.Read();
return TOKEN.CURLY_CLOSE;
case '[':
return TOKEN.SQUARED_OPEN;
case ']':
json.Read();
return TOKEN.SQUARED_CLOSE;
case ',':
json.Read();
return TOKEN.COMMA;
case '"':
return TOKEN.STRING;
case ':':
return TOKEN.COLON;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
return TOKEN.NUMBER;
}
switch (NextWord)
{
case "false":
return TOKEN.FALSE;
case "true":
return TOKEN.TRUE;
case "null":
return TOKEN.NULL;
}
return TOKEN.NONE;
}
}
}
sealed class Serializer
{
StringBuilder builder;
Serializer()
{
builder = new StringBuilder();
}
public static string Serialize(object obj)
{
var instance = new Serializer();
instance.SerializeValue(obj);
return instance.builder.ToString();
}
void SerializeValue(object value)
{
IList asList;
IDictionary asDict;
string asStr;
if (value == null)
{
builder.Append("null");
}
else if ((asStr = value as string) != null)
{
SerializeString(asStr);
}
else if (value is bool)
{
builder.Append((bool)value ? "true" : "false");
}
else if ((asList = value as IList) != null)
{
SerializeArray(asList);
}
else if ((asDict = value as IDictionary) != null)
{
SerializeObject(asDict);
}
else if (value is char)
{
SerializeString(new string((char)value, 1));
}
else
{
SerializeOther(value);
}
}
void SerializeObject(IDictionary obj)
{
bool first = true;
builder.Append('{');
foreach (object e in obj.Keys)
{
if (!first)
{
builder.Append(',');
}
SerializeString(e.ToString());
builder.Append(':');
SerializeValue(obj[e]);
first = false;
}
builder.Append('}');
}
void SerializeArray(IList anArray)
{
builder.Append('[');
bool first = true;
for (int i = 0; i < anArray.Count; i++)
{
object obj = anArray[i];
if (!first)
{
builder.Append(',');
}
SerializeValue(obj);
first = false;
}
builder.Append(']');
}
void SerializeString(string str)
{
builder.Append('\"');
char[] charArray = str.ToCharArray();
for (int i = 0; i < charArray.Length; i++)
{
char c = charArray[i];
switch (c)
{
case '"':
builder.Append("\\\"");
break;
case '\\':
builder.Append("\\\\");
break;
case '\b':
builder.Append("\\b");
break;
case '\f':
builder.Append("\\f");
break;
case '\n':
builder.Append("\\n");
break;
case '\r':
builder.Append("\\r");
break;
case '\t':
builder.Append("\\t");
break;
default:
int codepoint = Convert.ToInt32(c);
if ((codepoint >= 32) && (codepoint <= 126))
{
builder.Append(c);
}
else
{
builder.Append("\\u");
builder.Append(codepoint.ToString("x4"));
}
break;
}
}
builder.Append('\"');
}
void SerializeOther(object value)
{
// NOTE: decimals lose precision during serialization.
// They always have, I'm just letting you know.
// Previously floats and doubles lost precision too.
if (value is float)
{
builder.Append(((float)value).ToString("R", System.Globalization.CultureInfo.InvariantCulture));
}
else if (value is int
|| value is uint
|| value is long
|| value is sbyte
|| value is byte
|| value is short
|| value is ushort
|| value is ulong)
{
builder.Append(value);
}
else if (value is double
|| value is decimal)
{
builder.Append(Convert.ToDouble(value).ToString("R", System.Globalization.CultureInfo.InvariantCulture));
}
else
{
SerializeString(value.ToString());
}
}
}
}
}
+6 -1
View File
@@ -25,7 +25,12 @@ namespace Update
[STAThread]
static void Main(string[] args)
{
if (args.Length > 0)
//Program.oldVersion = 1332;
//Application.EnableVisualStyles();
//Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new MainForm());
//return;
if (args.Length > 0)
{
try
{
+2 -2
View File
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("1.1.0.0")]
[assembly: AssemblyFileVersion("1.1.0.0")]
+1
View File
@@ -62,6 +62,7 @@
<Compile Include="MainForm.designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="MiniJson.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="WebClientUtils.cs">