主頁 > .NET開發 > 遷移桌面程式到MS Store(11)——應用SVG圖示

遷移桌面程式到MS Store(11)——應用SVG圖示

2020-09-10 09:49:30 .NET開發

在傳統桌面程式中,對圖示的使用大多是直接嵌入JPG或者PNG的圖片,在祖傳的1366x768解析度下,并沒有什么問題,相對于手機硬體的突飛猛進,也側面反映了PC行業的落寞和桌面程式開發的不思進取,用360衛士的群眾并不能倒推PC行業的升級,反倒是水果公司雙高的利潤和口碑讓人很是眼饞,加之某軟跳出來教豬隊友做硬體,現在倒是有些起色,1080p的螢屏已是標配,4k也算常見,那么傳統桌面程式在升級程序中,就會遇到今天要討論的,如何解決高解析度下圖示模糊的問題,

一種解決方案是按最高的解析度提供圖片,這種適合較大的圖片,比如背景啥的,另一種就是今天要討論的,針對當前流行的、扁平化圖示的解決方案,

 從本篇的標題可以看出,我們希望應用SVG矢量圖來適應各種解析度的情況,以WPF程式為例,首先要面對的問題是,WPF并不支持像嵌入JPG/PNG圖示這樣,直接使用SVG圖示,大動干戈的參考第三方library通過自定義型別來支持SVG并不是本文的目的,這里我們要介紹如何通過字體檔案,進而在WPF或UWP中使用SVG圖示的方式,

雖然WPF不支持直接使用SVG檔案,但是Windows是支持矢量字體的,而我們的目的就是要將圖示以字體的形式在WPF程式中顯示,具體使用的字體TrueType,則是由微軟和蘋果共同開發的字體型別標準,該字體檔案的擴展名是.ttf,

https://en.wikipedia.org/wiki/TrueType

接下來我們依然是通過Sample工程來說明,首先給出GitHub的地址:

https://github.com/manupstairs/WpfAppForFontIcon

首先我們打開WpfAppWithPNGs工程,圖示的使用代碼如下:

        <Image Grid.Row="0" Grid.Column="0"  Width="32" Height="32" Source="Resources/Airplane_Off.png" ></Image>        <Image Grid.Row="0" Grid.Column="1"  Width="64" Height="64" Source="Resources/Airplane_On.png" ></Image>        <Image Grid.Row="0" Grid.Column="2"  Width="96" Height="96" Source="Resources/Bluetooth_Off.png"  ></Image>        <Image Grid.Row="0" Grid.Column="3"  Width="128" Height="128" Source="Resources/Bluetooth_On.png"  ></Image>

 

這里主要有兩個問題,因為我們默認提供的是32x32的圖示,因此除了第一列Width和Height設定為32的圖示,其他的圖示都存在模糊的問題,第二個問題是針對圖示的每一種顏色,都需要對應提供不同的圖示檔案(圖中的例子需要有灰色和藍色兩份檔案),相對的SVG圖示僅僅需要一份檔案,即可在程式中動態設定不同的顏色了,

這里先給出最終WPF專案中,對SVG圖示的參考的代碼,然后我們再進行詳細解釋,對應的工程名為WpfAppWithFontIcons,

        <TextBlock Grid.Row="0" Grid.Column="0" Text="{x:Static local:FontIcons.airplane_mode_circ}"   Foreground="Gray"  FontSize="32" ></TextBlock>        <TextBlock Grid.Row="0" Grid.Column="1" Text="{x:Static local:FontIcons.airplane_mode_circ}"  Foreground="{StaticResource dellBlue}"  FontSize="64" ></TextBlock>        <TextBlock Grid.Row="0" Grid.Column="2" Text="{x:Static local:FontIcons.bluetooth_inactive}"   Foreground="Orange"  FontSize="96" ></TextBlock>        <TextBlock Grid.Row="0" Grid.Column="3" Text="{x:Static local:FontIcons.bluetooth_inactive}"    Foreground="Brown"  FontSize="128" ></TextBlock>

代碼最大的不同應該是由<Image/>標簽更改為<TextBlock/>標簽,這是因為我們是通過ttf字體檔案,曲線救國的方式來使用SVG圖示,

具體的步驟如下:

準備SVG圖示檔案,將這些檔案打包成一整個ttf字體檔案,打包的方式有很多種,通常我使用的是IcoMoon的免費解決方案,地址如下:

https://icomoon.io/app/#/select

通過這個網站選擇SVG圖示檔案上傳,打包生成一個zip檔案,解壓后檔案夾結構如下圖:

ttf檔案在fonts檔案夾中,實際使用時,需要作為資源檔案,添加到WPF工程中,點擊圖中的demo.html會打開一個本地網頁,可用于查找ttf檔案中包含的SVG圖示,以及對應的unicode,實際我們是通過對unicode的參考來顯示SVG圖示的,

完整的project結構如下圖,Fonts檔案夾是手動添加用來放置ttf檔案,ttf檔案名字都是根據專案需要來取,并不固定,

ttf字體檔案需要以<FontFamily/>的形式添加到專案的<Resources/>節點中,然后再通過<Style/>指定給<TextBlock/>,當然不在<Resources/>節點定義Style,而是在每個<TextBlock/>中指定FontFamily屬性也是可以的,有關XAML的語法細節,回字的四種寫法什么的,這里略過不提,

    <Window.Resources>        <FontFamily x:Key="Fonticon">/Fonts/rcc-fonticon-ribbon-v2.ttf#rcc-fonticon-ribbon-v2</FontFamily>        <Style TargetType="TextBlock">            <Setter Property="FontFamily" Value="{StaticResource Fonticon}" ></Setter>        </Style>        <SolidColorBrush x:Key="dellBlue">#007DB8</SolidColorBrush>    </Window.Resources>

這里說明一下“/Fonts/rcc-fonticon-ribbon-v2.ttf#rcc-fonticon-ribbon-v2”值的定義,#前面的是檔案路徑,#后面的是font name,查看的方法是雙擊ttf檔案,參考下圖,

在定義好FontFamily之后,我們并不推薦直接將unicode寫到XAML或.cs檔案中,因為在XAML中,你需要如下撰寫:

<TextBlock Grid.Row="0" Grid.Column="0" Text="&#xe900;" Foreground="Gray"  FontSize="32" ></TextBlock>

而在C#代碼中,又需要以下面這種格式:

textBlockAirplane.Text = "\ue900"

兩種不統一的格式會在將來修改時帶來極大的困難,特別是圖示被多處參考時,全域的查找替換根本就是噩夢,此外,毫無意義的unicode值的可讀性根本等于0,正常人類無法將"&#xe900;","\ue900"和Airplane的圖示聯系起來,

我推薦的做法是生成一個FontIcons Class,以string型別屬性的形式暴露出來,這樣可以獲得IDE智能語法提示的支持,更新時也僅需修改這個Class,Find All Reference更是方便無比,同時無論在XAML檔案,還是C#代碼中,我們看到的都是統一的“FontIcons.airplane_mode_circ”,

    public static class FontIcons    {        public static string airplane_mode_circ { get; } = "\ue900";        public static string bluetooth_inactive { get; } = "\ue901";        public static string brightness { get; } = "\ue902";        public static string brightness_inactive { get; } = "\ue903";        public static string browse_inactive { get; } = "\ue904";        public static string camera { get; } = "\ue905";    }

那么我們是不是需要手工來撰寫FontIcons Class呢?大哥我們是能把午飯(我不愛喝咖啡)轉換成Code的生物啊!當然是寫個小工具來自動生成了,在Sample庫中,參考IcoMoonReader工程,只需將IcoMoon生成的.svg檔案(icomoon.zip解壓后的fonts檔案夾里)丟在IconMoonReader.exe同級目錄,即可生成相應代碼,

 其實只有一個方法啦,使用時需要注意具體的檔案名是否正確,

            using (var stream = new FileStream("rcc-fonticon-ribbon-v2.svg", FileMode.Open))            {                using (var reader = new StreamReader(stream))                {                    var pattern = "unicode(\\S)*\\sglyph-name(\\S)*\"";                    var input = reader.ReadToEnd();                    foreach (Match match in Regex.Matches(input, pattern))                    {                        pattern = "\"\\S*\"";                        var list = new List<string>();                        foreach (var result in Regex.Matches(match.Value, pattern))                        {                            list.Insert(0, result.ToString());                        }                        var name = list[0].Replace("\"", "").Replace("-","_");                        var code = list[1].Replace("&#x", "\\u").Replace(";", "");                        Console.WriteLine($"public static string {name} {{ get; }} = {code};");                    }                }            }

把生成的C#字串定義貼到具體工程的FontIcons Class(名字隨意),

這樣一個優秀的解決方案如果僅支持WPF,那又談何遷移到MS Store呢?實際上這套機制放到UWP工程中也是可以的,雖然UWP可以通過SvgImageSource屬性原生支持SVG了,但我們的這套方案在圖示的應用方面毫不遜色,甚至可以說更為方便,具體的例子可以參考AppWithFontIcon工程,在這個UWP的工程中,除了放ttf檔案的位置我換到了現成的Assets檔案夾,幾乎沒有改變,

        <TextBlock Grid.Row="0" Grid.Column="0" Text="{x:Bind local:FontIcons.airplane_mode_circ}"   Foreground="Gray"  FontSize="32" ></TextBlock>        <TextBlock Grid.Row="0" Grid.Column="1" Text="{x:Bind local:FontIcons.airplane_mode_circ}"  Foreground="{StaticResource dellBlue}"  FontSize="64" ></TextBlock>        <TextBlock Grid.Row="0" Grid.Column="2" Text="{x:Bind local:FontIcons.bluetooth_inactive}"   Foreground="Orange"  FontSize="96" ></TextBlock>        <TextBlock Grid.Row="0" Grid.Column="3" Text="{x:Bind local:FontIcons.bluetooth_inactive}"    Foreground="Brown"  FontSize="{x:Bind DynamicFontSize(),Mode=OneWay,FallbackValue=https://www.cnblogs.com/manupstairs/p/128}" ></TextBlock>

因為UWP沒有了x:static關鍵字,所以我換成了x:Bind,換成x:Bind之后甚至可以動態的回應值的變化,比如我在這里把FontSize做了一個x:bind到DynamicFontSize()方法,讓字體隨著界面改變,動態的變大變小,雖然并沒有什么卵用……但是Demo的時候可以增加點噱頭……

本篇到此結束,照例貼上Github地址:

https://github.com/manupstairs/WpfAppForFontIcon

感謝耐著性子看到這里的同學!

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/1701.html

標籤:UWP

上一篇:[UWP]使用CompositionAPI的翻轉影片

下一篇:[UWP]使用Win2D的BorderEffect實作圖片的平鋪功能

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more