身為性急又沒耐心的現代王藍田,我習慣為日常作業寫小工具放在桌面,需要時點兩下,避免被瑣事影響心情。簡單作業會用 PowerShell 寫,邏雜複雜的則會開個 Console Application 專案用 C# 開發。

.NET 6 推出的 Top-Level Statements 神奇地簡化 Program.cs 複雜度,有許多老人不習慣,我卻愛不釋手,它的出現讓寫小工具像喝水一樣簡單。

例如,我想做個點兩下上傳當日資料的小工具,整個專案只用到一個 Program.cs,短短幾行搞定,再配合 dotnet publish -c Release -r win-x64 --self-contained -p:PublishSingleFile=true 指令 可編譯成單一 exe 檔放在桌面,需要時點兩下完成上傳,很方便吧?

程式提供執行結果資訊有助提升使用者體驗,我常用的小技巧是成功時 Console.WriteLine 印出訊息,Thread.Sleep 停兩秒後再關閉視窗,出錯時則印出錯誤訊息並 Console.ReadLine() 確認使用者接收後按鍵關閉。

程式碼如下:

try {
    var uploadedCount = SimulateUpload();
    Console.WriteLine($"已成功上傳{uploadedCount}筆");
    Thread.Sleep(2000);
}
catch (Exception ex) {
    Console.ForegroundColor = ConsoleColor.DarkRed;
    Console.WriteLine(ex.Message);
    Console.ReadLine();
}

int SimulateUpload() {
    //模擬上傳作業
    var rnd = new Random();
    if (rnd.Next() % 3 == 1) 
        throw new ApplicationException("隨機模擬上傳失敗");
    Thread.Sleep(1500 + rnd.Next(3000));
    return rnd.Next(5) + 1;
}

這樣的設計差不多已滿足日常使用,操作流程也算順暢,若要挑剔,就是每次執行會跳出黑黑大大的命令列視窗,感覺十分突兀,不像一般人所認知的桌面應用程式。

這篇文章會來改造 .NET 6 Console Application 專案,試著讓它更優雅,更像「桌面應用程式」。

第一步,讓 .exe 執行時不要跳出黑黑命令列視窗。超簡單,將 csproj 的 <OutputType>Exe</OutputType> 改成 <OutputType>WinExe</OutputType> 就可以了,程式將默默開始、默默結束,不再出現命令列視窗。

但小工具需要顯示執行結果或錯誤訊息,此時 Windows Form 的 MessageBox 是個簡便選擇。要在 Console 專案使用 MessageBox,我們要修改 csproj,加上 <UseWindowsForms>true</UseWindowsForms>,TargetFramework 則要由 net6.0 改成 net6.0-windows:

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <UseWindowsForms>true</UseWindowsForms>
    <TargetFramework>net6.0-windows</TargetFramework>
    <RootNamespace>better_console_tool</RootNamespace>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

如此,我們就能在 Console 程式呼叫 MessageBox.Show(),程式修改如下:

try {
    var uploadedCount = SimulateUpload();
    ShowMessage($"已成功上傳{uploadedCount}筆");
}
catch (Exception ex) {
    ShowMessage(ex.Message);
}
void ShowMessage(string msg) {
    System.Windows.Forms.MessageBox.Show(msg, "上傳作業");
}
int SimulateUpload() {
    //模擬上傳作業
    var rnd = new Random();
    if (rnd.Next() % 3 == 1) 
        throw new ApplicationException("隨機模擬上傳失敗");
    Thread.Sleep(1500 + rnd.Next(3000));
    return rnd.Next(5) + 1;
}

經過這番修改,Console 小工具的表現已接近一般桌面程式了,但我想更上一層樓,讓狀態顯示更貼心:作業過程顯示上傳中,作業完成顯示上傳筆數,兩秒後自動關閉。

因為我們已啟用 UseWindowsForms,除了 MessageBox,要建立及顯示 Windows Form 也不是問題,因此我簡單建了 Form 加入 Label 顯示文字,並支援顯示兩秒自動關閉,將程式改寫如下:

var form = new Form() {
    FormBorderStyle = FormBorderStyle.None, StartPosition = FormStartPosition.CenterScreen,
    TopMost = true, ControlBox = false, ShowInTaskbar = false, Opacity = 0.8, Width = 0, Height = 0
};
var lbl = new Label() {
    Padding = new Padding(8), AutoSize = true, Font = new Font("微軟正黑體", 12, FontStyle.Bold),
    BackColor = Color.Coral
};
form.Controls.Add(lbl);
form.Show();
var startX = form.Left;
void ShowInfo(string message) {
    lbl.Text = message;
    form.Width = lbl.Width;
    form.Height = lbl.Height;
    form.Left = startX - form.Width / 2;
    form.Refresh();
}
try {
    ShowInfo("上傳中...");
    var uploadedCount = SimulateUpload();
    ShowInfo($"已成功上傳{uploadedCount}筆");
    Thread.Sleep(2000);
    form.Close();
}
catch (Exception ex) {
    ShowMessage(ex.Message);
}
void ShowMessage(string msg) {
    System.Windows.Forms.MessageBox.Show(msg, "上傳作業");
}

int SimulateUpload() {
    //模擬上傳作業
    var rnd = new Random();
    if (rnd.Next() % 3 == 1) 
        throw new ApplicationException("隨機模擬上傳失敗");
    Thread.Sleep(1500 + rnd.Next(3000));
    return rnd.Next(5) + 1;
}

然後,我們可以幫 Console 程式換個有鑑別度的圖示,找個 .ico 圖示檔,在 csproj 加上 <ApplicationIcon>hotplug.ico</ApplicationIcon> 換掉單調的預設圖示。

最後成品如下:

跟最初的版本比較,是不是高級多了?

範例專案我放上 Github 了,分享給愛寫 .NET 6 Console 小工具的朋友。

Tutorial of how to provide better user experience for your console application desktop tool.


Comments

# by SY

其實就是邏輯寫在program.cs的winform?

# by Iyy

跟java swing 很像。

# by Joker

6 真的很解放,很自由 跨平台靈活度超高,讚啦

Post a comment