循序漸進介紹基於CommunityToolkit.Mvvm 和HandyControl的WPF應用端開發(4) -- 實現DataGrid數據的導入和導出操作

来源:https://www.cnblogs.com/wuhuacong/archive/2023/09/18/17711356.html
-Advertisement-
Play Games

在我們設計軟體的很多地方,都看到需要對錶格數據進行導入和導出的操作,主要是方便客戶進行快速的數據處理和分享的功能,本篇隨筆介紹基於WPF實現DataGrid數據的導入和導出操作。 ...


在我們設計軟體的很多地方,都看到需要對錶格數據進行導入和導出的操作,主要是方便客戶進行快速的數據處理和分享的功能,本篇隨筆介紹基於WPF實現DataGrid數據的導入和導出操作。

1、系統界面設計

在我們實現數據的導入導出功能之前,我們在主界面需要提供給客戶相關的操作按鈕,如下界面所示,在列表的頂端提供導入Excel、導出PDF、導出Excel。

由於這些操作功能基本上在各個頁面模塊,可能都會用到,因此儘可能的抽象到基類,以及提供通用的處理操作,實在有差異的,也可以通過一些屬性或者事件方法的覆蓋方式來實現即可。

因此我們在Xaml裡面定義按鈕的時候,基本上是調用視圖模型的方法來通用化的處理,如下代碼所示。

<Button
    Margin="5"
    hc:IconElement.Geometry="{StaticResource t_import}"
    Command="{Binding ImportExcelCommand}"
    Content="導入Excel"
    Style="{StaticResource ButtonWarning}" />
<Button
    Margin="5"
    hc:IconElement.Geometry="{StaticResource SaveGeometry}"
    Command="{Binding ViewModel.ExportPdfCommand}"
    CommandParameter="用戶信息列表"
    Content="導出PDF"
    Style="{StaticResource ButtonSuccess}" />
<Button
    Margin="5"
    hc:IconElement.Geometry="{StaticResource SaveGeometry}"
    Command="{Binding ViewModel.ExportExcelCommand}"
    CommandParameter="用戶信息列表"
    Content="導出Excel"
    Style="{StaticResource ButtonSuccess}" />

而導入的處理操作函數ImportExcelComand的定義如下所示(註意這裡聲明瞭RelayCommand)代碼會自動生成Command的尾碼Command方法的。

    /// <summary>
    /// 導出內容到Excel
    /// </summary>
    [RelayCommand]
    private void ImportExcel()
    {
        var page = App.GetService<ImportExcelData>();
        page!.ViewModel.Items?.Clear();
        page!.ViewModel.TemplateFile = $"系統用戶信息-模板.xls";
        page!.OnDataSave -= ExcelData_OnDataSave;
        page!.OnDataSave += ExcelData_OnDataSave;

        //導航到指定頁面
        ViewModel.Navigate(typeof(ImportExcelData));
    }

而其中 ImportExcelData 是我們定義的通用導入頁面窗體類,這裡只需要實現一些屬性的設置(根據子類的不同而調整,後期可以用代碼生成工具生成),以及一些事件用於子類延後實現,從而可以實現自定義的數據處理的功能。

我們在下麵再細說批量導入的處理細節。

 

2、數據導出到Excel

數據導出到Excel,在我們的Winform端中很常見,而WPF這裡也是一樣的處理方式,通用利用Excel的操作組件的封裝類來實現,可以基於NPOI,也可以基於Aspose.Cell實現,根據自己的需要實現簡單的封裝調用即可。

導出到Excel,首先需要彈出選擇目錄的對話框進行選取目錄,然後用於生成Excel的文件,如下界面所示。

這個處理,由於WPF可以調用.net裡面的System.Windows.Forms,因此我們直接調用裡面的對話框處理封裝即可,這個類來自於我們的Winform的UI公用類庫部分。

在前面隨筆,我們介紹過為了WPF開發的方便,我們設計了幾個視圖基類,用於減少代碼的處理。

對於不同的業務類,我們也只需要根據實際情況,生成對應的業務視圖模型類即可。

我們把通用的導出操作放到了這個視圖基類BaseListViewModel 裡面即可,如下代碼所示。

/// <summary>
/// 觸發導出Excel處理命令
/// </summary>
[RelayCommand]
protected virtual async Task ExportExcel(string title = "列表數據")
{
    var table = await this.ConvertItems(this.Items);
    BaseExportExcel(table, title);
}

而其中對於DataTable的處理Excel,提供一個通用的方法。

    /// <summary>
    /// 可供重寫的基類函數,導出Excel
    /// </summary>
    public virtual void BaseExportExcel(DataTable table, string title = "列表數據")
    {
        string file = FileDialogHelper.SaveExcel(string.Format("{0}.xls", title));
        if (!string.IsNullOrEmpty(file))
        {
            try
            {
                string error = "";
                AsposeExcelTools.DataTableToExcel2(table, file, out error);

                if (!string.IsNullOrEmpty(error))
                {
                    MessageDxUtil.ShowError(string.Format("導出Excel出現錯誤:{0}", error));
                }
                else
                {
                    if (MessageDxUtil.ShowYesNoAndTips("導出成功,是否打開文件?") == System.Windows.MessageBoxResult.Yes)
                    {
                        Process.Start("explorer.exe", file);
                    }
                }
            }
            catch (Exception ex)
            {
                LogTextHelper.Error(ex);
                MessageDxUtil.ShowError(ex.Message);
            }
        }
    }

其中FileDialogHelper.SaveExcel 的代碼如下所示。

/// <summary>
/// 保存Excel對話框,並返回保存全路徑
/// </summary>
/// <returns></returns>
public static string SaveExcel(string filename, string initialDirectory)
{
    return Save("保存Excel", ExcelFilter, filename, initialDirectory);
} 

/// <summary>
/// 以指定的標題彈出保存文件對話框
/// </summary>
/// <param name="title">對話框標題</param>
/// <param name="filter">尾碼名過濾</param>
/// <param name="filename">預設文件名</param>
/// <param name="initialDirectory">初始化目錄</param>
/// <returns></returns>
public static string Save(string title, string filter, string filename, string initialDirectory)
{
    //多語言支持
    title = JsonLanguage.Default.GetString(title);

    var dialog = new SaveFileDialog();
    dialog.Filter = filter;
    dialog.Title = title;
    dialog.FileName = filename;
    dialog.RestoreDirectory = true;
    if (!string.IsNullOrEmpty(initialDirectory))
    {
        dialog.InitialDirectory = initialDirectory;
    }

    if (dialog.ShowDialog() == DialogResult.OK)
    {
        return dialog.FileName;
    }
    return string.Empty;
}

而其中SaveFileDialog是屬於.net 中System.Windows.Forms裡面的內容,WPF可以直接調用。

而DataTableToExcel2 方法,這是我們封裝的一個使用Aspose.Cell的調用,主要用於快速處理DataTable到Excel的操作封裝,我們也可可以利用其它操作Excel的封裝,如NPOI等都可以實現。

代碼如下所示。

/// <summary>
/// 把DataTabel轉換成Excel文件
/// </summary>
/// <param name="datatable">DataTable對象</param>
/// <param name="filepath">目標文件路徑,Excel文件的全路徑</param>
/// <param name="error">錯誤信息:返回錯誤信息,沒有錯誤返回""</param>
/// <returns></returns>
public static bool DataTableToExcel2(DataTable datatable, string filepath, out string error)
{
    error = "";
    var wb = new Aspose.Cells.Workbook();

    try
    {
        if (datatable == null)
        {
            error = "DataTableToExcel:datatable 為空";
            return false;
        }

        //為單元格添加樣式    
        var style = wb.CreateStyle();
        //設置居中
        style.HorizontalAlignment = Aspose.Cells.TextAlignmentType.Center;
        //設置背景顏色
        style.ForegroundColor = System.Drawing.Color.FromArgb(153, 204, 0);
        style.Pattern = BackgroundType.Solid;
        style.Font.IsBold = true;

        int rowIndex = 0;
        for (int i = 0; i < datatable.Columns.Count; i++)
        {
            DataColumn col = datatable.Columns[i];
            string columnName = col.Caption ?? col.ColumnName;
            wb.Worksheets[0].Cells[rowIndex, i].PutValue(columnName);
            wb.Worksheets[0].Cells[rowIndex, i].SetStyle(style);
        }
        rowIndex++;

        foreach (DataRow row in datatable.Rows)
        {
            for (int i = 0; i < datatable.Columns.Count; i++)
            {
                wb.Worksheets[0].Cells[rowIndex, i].PutValue(row[i].ToString());
            }
            rowIndex++;
        }

        for (int k = 0; k < datatable.Columns.Count; k++)
        {
            wb.Worksheets[0].AutoFitColumn(k, 0, 150);
        }
        wb.Worksheets[0].FreezePanes(1, 0, 1, datatable.Columns.Count);
        wb.Save(filepath);
        return true;
    }
    catch (Exception e)
    {
        error = error + " DataTableToExcel: " + e.Message;
        return false;
    }

}

導出Excel的內容如下界面所示。另外導出文檔的內容,我們可以用於導入的數據模板的。

我們可以根據需要設置要導出的列即可。

 

3、數據導出到PDF

同樣,數據導出到PDF的處理操作類似,也是通過視圖基類的封裝方法,實現快速的導出到PDF處理,如下是視圖基類裡面的實現方法。

/// <summary>
/// 觸發導出PDF處理命令
/// </summary>
[RelayCommand]
protected virtual async Task ExportPdf(string title = "列表數據")
{
    var table = await this.ConvertItems(this.Items);
    BaseExportPdf(table, title);
}

/// <summary>
/// 可供重寫的基類函數,導出PDF
/// </summary>
public virtual void BaseExportPdf(DataTable table, string title = "列表數據")
{
    var pdfFile = FileDialogHelper.SavePdf();
    if (!pdfFile.IsNullOrEmpty())
    {
        bool isLandscape = true;//是否為橫向列印,預設為true
        bool includeHeader = true;//是否每頁包含表頭信息
        var headerAlignment = iText.Layout.Properties.HorizontalAlignment.CENTER;//頭部的對其方式,預設為居中
        float headerFontSize = 9f;//頭部字體大小
        float rowFontSize = 9f;//行記錄字體大小
        float? headerFixHeight = null;//頭部的固定高度,否則為自適應

        var success = TextSharpHelper.ExportTableToPdf(title, table, pdfFile, isLandscape, includeHeader, headerAlignment, headerFontSize, rowFontSize, headerFixHeight);

        //提示信息
        var message = success ? "導出操作成功" : "導出操作失敗";
        if (success)
        {
            Growl.SuccessGlobal(message);
            Process.Start("explorer.exe", pdfFile);
        }
        else
        {
            Growl.ErrorGlobal(message);
        }
    }
}

通過把List<T>的列表轉換為常規的DataTable來處理,我們就可以利用之前我們隨筆《在Winform分頁控制項中集成導出PDF文檔的功能》介紹到的PDF導出函數來實現WPF數據導出到PDF的處理。

上面的 TextSharpHelper 就是對於itext7進行的封裝,實現PDF的導出處理。

 引入相關的Nugget類後,封裝它的輔助類代碼如下所示。

    /// <summary>
    /// 基於iText7對PDF的導出處理
    /// </summary>
    public static class TextSharpHelper
    {
        /// <summary>
        /// datatable轉PDF方法
        /// </summary>
        /// <param name="title">標題內容</param>
        /// <param name="data">dataTable數據</param>
        /// <param name="pdfFile">PDF文件保存的路徑</param>
        /// <param name="isLandscape">是否為橫向列印,預設為true</param>
        /// <param name="includeHeader">是否每頁包含表頭信息</param>
        /// <param name="headerAlignment">頭部的對其方式,預設為居中對其</param>
        /// <param name="headerFontSize">頭部字體大小</param>
        /// <param name="rowFontSize">行記錄字體大小</param>
        /// <param name="headerFixHeight">頭部的固定高度,否則為自適應</param>
        /// <returns></returns>
        public static bool ExportTableToPdf(string title, DataTable data, string pdfFile, bool isLandscape = true, bool includeHeader = true, iText.Layout.Properties.HorizontalAlignment headerAlignment = iText.Layout.Properties.HorizontalAlignment.CENTER, float headerFontSize = 9f, float rowFontSize = 9f, float? headerFixHeight = null)
        {var writer = new PdfWriter(pdfFile);
            PdfDocument pdf = new PdfDocument(writer);
            pdf.SetDefaultPageSize(isLandscape ? PageSize.A4.Rotate() : PageSize.A4); //A4橫向
            var doc = new Document(pdf);//設置標題
            if (!string.IsNullOrEmpty(title))
            {
                var param = new Paragraph(title)
                         .SetFontColor(iText.Kernel.Colors.ColorConstants.BLACK)
                         .SetBold()  //粗體
                         .SetFontSize(headerFontSize + 5)
                         .SetTextAlignment(TextAlignment.CENTER); //居中
                doc.Add(param);
            }
            var table = new Table(data.Columns.Count)
                .SetTextAlignment(TextAlignment.CENTER)
                .SetVerticalAlignment(VerticalAlignment.MIDDLE)
                .SetWidth(new UnitValue(UnitValue.PERCENT, 100));//縮放比例
            table.UseAllAvailableWidth();
            //添加表頭
            foreach (DataColumn dc in data.Columns)
            {
                var caption = !string.IsNullOrEmpty(dc.Caption) ? dc.Caption : dc.ColumnName;
                var cell = new Cell().Add(new Paragraph(caption))
                    .SetBold()
                    .SetVerticalAlignment(VerticalAlignment.MIDDLE)
                    .SetHorizontalAlignment(headerAlignment)
                    .SetPadding(1)
                    .SetFontSize(headerFontSize);
                if (headerFixHeight.HasValue)
                {
                    cell.SetHeight(new UnitValue(UnitValue.POINT, headerFixHeight.Value));
                }
                table.AddHeaderCell(cell);
            }
            //插入數據
            var colorWhite = Color.ConvertRgbToCmyk(iText.Kernel.Colors.WebColors.GetRGBColor("White"));// System.Drawing.Color.White;
            var colorEvent = iText.Kernel.Colors.WebColors.GetRGBColor("LightCyan");// System.Drawing.Color.LightCyan;
            var EventRowBackColor = Color.ConvertRgbToCmyk(colorEvent);
            for (int i = 0; i < data.Rows.Count; i++)
            {
                table.StartNewRow();//第一列開啟新行
                var backgroudColor = ((i % 2 == 0) ? colorWhite : EventRowBackColor);
                for (int j = 0; j < data.Columns.Count; j++)
                {
                    var text = data.Rows[i][j].ToString();
                    var cell = new Cell()
                        .SetBackgroundColor(backgroudColor)
                        .SetFontSize(rowFontSize)
                        .SetVerticalAlignment(VerticalAlignment.MIDDLE)
                        .Add(new Paragraph(text));
                    table.AddCell(cell);
                }
            }
            doc.Add(table);
            pdf.Close();
            writer.Close();
            return true;
        }
    }

導出PDF的文檔效果如下所示。

 

4、導入Excel數據

 Excel數據的導入,可以降低批量處理數據的難度和繁瑣的界面一個個錄入,這種是一種常見的操作方式,我們主要提供固定的模板給客戶下載錄入數據,然後提交進行批量的導入即可。

導入的界面處理,我們這裡涉及一個通用的導入界面(和WInform端的界面類似),這樣我們每個不同的業務導入處理都可以重用,只需要設置一些不同的屬性,以及一些事件的處理即可,如下是通用的界面效果。

 我們這裡主要針對性的介紹它的設計方式,前面我們介紹,在業務界面裡面調用它的時候,如下代碼所示。

/// <summary>
/// 導出內容到Excel
/// </summary>
[RelayCommand]
private void ImportExcel()
{
    var page = App.GetService<ImportExcelData>();
    page!.ViewModel.Items?.Clear();
    page!.ViewModel.TemplateFile = $"系統用戶信息-模板.xls";
    page!.OnDataSave -= ExcelData_OnDataSave;
    page!.OnDataSave += ExcelData_OnDataSave;

    //導航到指定頁面
    ViewModel.Navigate(typeof(ImportExcelData));
}

這個通用的窗體裡面的視圖模型,定義了一個模板的文件名稱,以及一個通用的數據DataTable的集合,以及一個事件用於子類的導入轉換的實現,它的視圖模型類代碼如下所示。

    /// <summary>
    /// 批量導入Excel數據的視圖模型基類
    /// </summary>
    public partial class ImportExcelDataViewModel : BaseViewModel
    {
        [ObservableProperty]
        private string templateFile;

        [ObservableProperty]
        private string importFilePath;

        [ObservableProperty]
        private DataTable items;

我們為了給客戶打開模板文件,方便用於錄入Excel數據,因此我們在本地打開模板文件即可。

        /// <summary>
        /// 打開模板文件
        /// </summary>
        [RelayCommand]
        private void OpenFile()
        {
            if (!this.TemplateFile.IsNullOrEmpty())
            {
                var realFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, this.TemplateFile);
                if (File.Exists(realFilePath))
                {
                    Process.Start("explorer.exe", realFilePath);
                }
                else
                {
                    MessageDxUtil.ShowError($"沒有找到該模板文件:{realFilePath}");
                }
            }
        }

在通用的導入頁面的後臺代碼裡面,我們需要實現一些如選擇Excel後,顯示數據到DataGrid的操作,以及批量保存數據的處理。

        /// <summary>
        /// 選擇Excel文件後,顯示Excel裡面的表格數據
        /// </summary>
        [RelayCommand]
        private void BrowseExcel()
        {
            string file = FileDialogHelper.OpenExcel();
            if (!string.IsNullOrEmpty(file))
            {
                this.ViewModel.ImportFilePath = file;
                ViewData();
            }
        }    
        /// <summary>
        /// 查看Excel文件並顯示在界面上操作
        /// </summary>
        private void ViewData()
        {
            if (this.txtFilePath.Text == "")
            {
                MessageDxUtil.ShowTips("請選擇指定的Excel文件");
                return;
            }

            try
            {
                var myDs = new DataSet();

                string error = "";
                AsposeExcelTools.ExcelFileToDataSet(this.txtFilePath.Text, out myDs, out error);
                this.ViewModel.Items = myDs.Tables[0];
            }
            catch (Exception ex)
            {
                LogTextHelper.Error(ex);
                MessageDxUtil.ShowError(ex.Message);
            }
        }

導入處理的操作代碼如下所示。

/// <summary>
/// 批量保存數據到資料庫
/// </summary>
/// <returns></returns>
[RelayCommand]
private async Task<CommonResult> SaveData()
{            
    if (ViewModel.Items == null || ViewModel.Items?.Rows?.Count == 0)
        return new CommonResult(false);

    if (MessageDxUtil.ShowYesNoAndWarning("該操作將把數據導入到系統資料庫中,您確定是否繼續?") ==  System.Windows.MessageBoxResult.Yes)
    {
        var dt = this.ViewModel.Items;
        foreach (DataRow dr in dt.Rows)
        {
            try
            {
                await OnDataSave(dr);
            }
            catch (Exception ex)
            {
                LogTextHelper.Error(ex);
                MessageDxUtil.ShowError(ex.Message);
            }
        }
        return new CommonResult(true, "操作成功");
    }
    return new CommonResult(false);
}

註意,我們這裡使用了事件的處理,把數據的轉換邏輯留給子類去實現的。

        /// <summary>
        /// 數據保存的事件
        /// </summary>
        public event SaveDataHandler OnDataSave;

這樣我們在用戶信息的導入頁面UserListPage.xaml.cs裡面的代碼就可以根據實際的情況進行實現事件了。

    /// <summary>
    /// 導出內容到Excel
    /// </summary>
    [RelayCommand]
    private void ImportExcel()
    {
        var page = App.GetService<ImportExcelData>();
        page!.ViewModel.Items?.Clear();
        page!.ViewModel.TemplateFile = $"系統用戶信息-模板.xls";
        page!.OnDataSave -= ExcelData_OnDataSave;
        page!.OnDataSave += ExcelData_OnDataSave;

        //導航到指定頁面
        ViewModel.Navigate(typeof(ImportExcelData));
    }

這個事件的實現,主要就是把個性化的用戶信息(用戶信息模板裡面定義的欄位),轉換為DataTable的行信息即可,如下代碼所示。具體根據模板設計的情況進行修改即可。

具體就不再一一贅述,主要就是基類邏輯和具體實現分離,實現不同的業務功能處理即可。

以上即是我們一個列表通用頁面裡面,往往需要用到的通用性的導入、導出操作的介紹,希望對讀者在開發WPF應用功能上有所啟發,有所參考,善莫大焉。

專註於代碼生成工具、.Net/.NetCore 框架架構及軟體開發,以及各種Vue.js的前端技術應用。著有Winform開發框架/混合式開發框架、微信開發框架、Bootstrap開發框架、ABP開發框架、SqlSugar開發框架等框架產品。
  轉載請註明出處:撰寫人:伍華聰  http://www.iqidi.com 
    

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • JDK21 計劃23年9月19日正式發佈,雖然一直以來都是“版本隨便出,換 8 算我輸”,但這麼多年這麼多版本的折騰,如果說之前的 LTS版本JDK17你還覺得不香,那 JDK21還是有必要關註一下,因為會有一批重要更新發佈到生產環境中,特別是千呼萬喚的虛擬線程,雖然說這東西我感覺不需要的用不到,需 ...
  • 前言 MongoDB是一個基於分散式文件存儲的開源資料庫系統,使用C++語言編寫。它是一個介於關係資料庫和非關係資料庫之間的產品,具有類似關係資料庫的功能,但又有一些非關係資料庫的特點。MongoDB的數據模型比較鬆散,採用類似json的bson格式,可以靈活地存儲各種類型的數據 MongoDB的優 ...
  • gRPC 是開發中常用的開源高性能遠程過程調用(RPC)框架,tonic 是基於 HTTP/2 的 gRPC 實現,專註於高性能、互操作性和靈活性。該庫的創建是為了對 async/await 提供一流的支持,並充當用 Rust 編寫的生產系統的核心構建塊。今天我們聊聊通過使用tonic 調用grpc... ...
  • 來源:虛無境的博客 地址:www.cnblogs.com/xuwujing/p/11953697.html 在介紹Nginx的負載均衡實現之前,先簡單的說下負載均衡的分類,主要分為硬體負載均衡和軟體負載均衡,硬體負載均衡是使用專門的軟體和硬體相結合的設備,設備商會提供完整成熟的解決方案,比如F5,在 ...
  • CRC校驗技術是用於檢測數據傳輸或存儲過程中是否出現了錯誤的一種方法,校驗演算法可以通過計算應用與數據的迴圈冗餘校驗(CRC)檢驗值來檢測任何數據損壞。通過運用本校驗技術我們可以實現對特定記憶體區域以及磁碟文件進行完整性檢測,並以此來判定特定程式記憶體是否發生了變化,如果發生變化則拒絕執行,通過此種方法來... ...
  • 近些年來,隨著WPF在生產,製造,工業控制等領域應用越來越廣發,很多企業對WPF開發的需求也逐漸增多,使得很多人看到潛在機會,不斷從Web,WinForm開發轉向了WPF開發,但是WPF開發也有很多新的概念及設計思想,如:數據驅動,數據綁定,依賴屬性,命令,控制項模板,數據模板,MVVM等,與傳統Wi... ...
  • 在我們展示一些參考信息的時候,有所會用樹形列表來展示結構信息,如對於有父子關係的多層級部門機構,以及一些常用如字典大類節點,也都可以利用樹形列表的方式進行展示,本篇隨筆介紹基於WPF的方式,使用TreeView來洗實現結構信息的展示,以及對它的菜單進行的設置、過濾查詢等功能的實現邏輯。 ...
  • 有關mmd播放器,網上也有許多非常漂亮的實現,如 pmxeditor、saba、blender_mmd_tools等等。。 首先我想先介紹下我參考實現的倉庫: sselecirPyM/Coocoo3D: Experimental MMD renderer using DX12 and DXR. (g ...
一周排行
    -Advertisement-
    Play Games
  • 一個自定義WPF窗體的解決方案,借鑒了呂毅老師的WPF製作高性能的透明背景的異形視窗一文,併在此基礎上增加了滑鼠穿透的功能。可以使得透明窗體的滑鼠事件穿透到下層,在下層窗體中響應。 ...
  • 在C#中使用RabbitMQ做個簡單的發送郵件小項目 前言 好久沒有做項目了,這次做一個發送郵件的小項目。發郵件是一個比較耗時的操作,之前在我的個人博客裡面回覆評論和友鏈申請是會通過發送郵件來通知對方的,不過當時只是簡單的進行了非同步操作。 那麼這次來使用RabbitMQ去統一發送郵件,我的想法是通過 ...
  • 當你使用Edge等瀏覽器或系統軟體播放媒體時,Windows控制中心就會出現相應的媒體信息以及控制播放的功能,如圖。 SMTC (SystemMediaTransportControls) 是一個Windows App SDK (舊為UWP) 中提供的一個API,用於與系統媒體交互。接入SMTC的好 ...
  • 最近在微軟商店,官方上架了新款Win11風格的WPF版UI框架【WPF Gallery Preview 1.0.0.0】,這款應用引入了前沿的Fluent Design UI設計,為用戶帶來全新的視覺體驗。 ...
  • 1.簡單使用實例 1.1 添加log4net.dll的引用。 在NuGet程式包中搜索log4net並添加,此次我所用版本為2.0.17。如下圖: 1.2 添加配置文件 右鍵項目,添加新建項,搜索選擇應用程式配置文件,命名為log4net.config,步驟如下圖: 1.2.1 log4net.co ...
  • 之前也分享過 Swashbuckle.AspNetCore 的使用,不過版本比較老了,本次演示用的示例版本為 .net core 8.0,從安裝使用開始,到根據命名空間分組顯示,十分的有用 ...
  • 在 Visual Studio 中,至少可以創建三種不同類型的類庫: 類庫(.NET Framework) 類庫(.NET 標準) 類庫 (.NET Core) 雖然第一種是我們多年來一直在使用的,但一直感到困惑的一個主要問題是何時使用 .NET Standard 和 .NET Core 類庫類型。 ...
  • WPF的按鈕提供了Template模板,可以通過修改Template模板中的內容對按鈕的樣式進行自定義。結合資源字典,可以將自定義資源在xaml視窗、自定義控制項或者整個App當中調用 ...
  • 實現了一個支持長短按得按鈕組件,單擊可以觸發Click事件,長按可以觸發LongPressed事件,長按鬆開時觸發LongClick事件。還可以和自定義外觀相結合,實現自定義的按鈕外形。 ...
  • 一、WTM是什麼 WalkingTec.Mvvm框架(簡稱WTM)最早開發與2013年,基於Asp.net MVC3 和 最早的Entity Framework, 當初主要是為瞭解決公司內部開發效率低,代碼風格不統一的問題。2017年9月,將代碼移植到了.Net Core上,併進行了深度優化和重構, ...