Windows Community Toolkit 3.0 - InfiniteCanvas

来源:https://www.cnblogs.com/shaomeng/archive/2018/08/12/9281065.html
-Advertisement-
Play Games

概述 InfiniteCanvas 是一個 Canvas 控制項,它支持無限畫布的滾動,支持 Ink,文本,格式文本,畫布縮放操作,撤銷重做操作,導入和導出數據。 這是一個非常實用的控制項,在“來畫視頻” UWP 應用的繪畫功能中,也用到了這個控制項,它對不同畫筆的選擇,橡皮擦,直尺和圓形尺,文字輸入和字 ...


概述

InfiniteCanvas 是一個 Canvas 控制項,它支持無限畫布的滾動,支持 Ink,文本,格式文本,畫布縮放操作,撤銷重做操作,導入和導出數據。

這是一個非常實用的控制項,在“來畫視頻” UWP 應用的繪畫功能中,也用到了這個控制項,它對不同畫筆的選擇,橡皮擦,直尺和圓形尺,文字輸入和字體選擇等都提供了很便捷的支持,而且支持導入和導出數據,可以很方便的創作繪畫作品,並能導出和分享給別人。 

下麵是 Windows Community Toolkit Sample App 的示例截圖和 code/doc 地址:

Windows Community Toolkit Doc - InfiniteCanvas

Windows Community Toolkit Source Code - InfiniteCanvas

Namespace: Microsoft.Toolkit.Uwp.UI.Controls; Nuget: Microsoft.Toolkit.Uwp.UI.Controls;

 

開發過程

代碼結構分析

首先來看 InfiniteCanvas 的代碼結構,組成如下:

  • Commands - InfiniteCanvas 對應的所有命令,包括 redo/undo,Ink,Text 等,如上面示例圖中 Toolbar 上所示;
  • Controls - InfiniteCanvas 的主要控制項都在這個文件夾里;
  • Drawables - Text 和 Ink 主要的繪製功能在這個文件夾里;
  • JsonConverters - 序列化和反序列化的主要功能,以及自定義的 Ink 屬性等;
  • InfiniteCanvas.Events.cs - InfiniteCanvas 的主要事件處理邏輯;
  • InfiniteCanvas.TextBox.cs - InfiniteCanvas 添加文字的文本框控制項處理邏輯;
  • InfiniteCanvas.cs - InfiniteCanvas 控制項的主要處理邏輯;
  • InfiniteCanvas.xaml - InfiniteCanvas 控制項的 XAML 樣式文件;

 

InfiniteCanvas 整體類結構很清晰,每個類的功能也很明確,下麵我們選取幾個重要的類來做分析。

1.  InfiniteCanvasCreateInkCommand

Command 文件夾的每一個類都比較簡單,我們找一個創建 Ink 命令看一下;該類實現了 IInfiniteCanvasCommand 這個介面,實現了 Execute() 和 Undo() 兩個方法;Command 初始化也很簡單,創建一個 InkDrawable 對象,初始化 drawableList 對象,執行創建時加入該 drawable,撤銷時把它從 drawableList 中去掉。  

internal class InfiniteCanvasCreateInkCommand : IInfiniteCanvasCommand
{
    private readonly List<IDrawable> _drawableList;
    private readonly InkDrawable _drawable;

    public InfiniteCanvasCreateInkCommand(List<IDrawable> drawableList, IReadOnlyList<InkStroke> strokes)
    {
        _drawable = new InkDrawable(strokes);
        _drawableList = drawableList;
    }

    public void Execute()
    {
        _drawableList.Add(_drawable);
    }

    public void Undo()
    {
        _drawableList.Remove(_drawable);
    }
}

2. InfiniteCanvasTextBox

用於 InfiniteCanvas 的文本框控制項,從下圖的結構中可以看到完整的文本框屬性定義方法,包括設置文字,設置編輯區域尺寸,文字變化的處理,游標位置的限制等。

來看一下判斷游標能夠下移一行的 CannotGoDown() 方法,按照換行符來切割文字行,如果只有一行則不可下移;當前選擇的結束,在最後一行時,也不可下移,其他情況都可以下移;

internal bool CannotGoDown()
{
    var lines = _editZone.Text.Split('\r');
    if (lines.Count() == 1)
    {
        return true;
    }

    var lastLine = lines.ElementAt(lines.Length - 1);
    if ((_editZone.Text.Length - lastLine.Length) <= (_editZone.SelectionStart + _editZone.SelectionLength))
    {
        return true;
    }

    return false;
}

3. InfiniteCanvasVirtualDrawingSurface

用於渲染 Ink 和 Text 的虛擬 drawing surface,它有幾個部分類組成:

主要的處理邏輯,是利用 Commands 來操作 Ink 和 Text 的渲染執行和撤銷操作,計算渲染的尺寸空間,組織渲染的內容。

4. InkDrawable 和 TextDrawable

Ink 和 Text 可繪畫元素的繪畫邏輯,分別來看一下兩個類的組成:

 

我們看一下兩個類的 Draw 方法:

Draw() - InkDrawable:

獲得 Strokes 中每個線條的每個點,加入到集合中,從點集合創建線條,最後生成新的 Stroke 列表;遍歷完成後,把新的 Stroke 列表用於 drawingSession 的 DrawInk 方法來實現繪製; 

public void Draw(CanvasDrawingSession drawingSession, Rect sessionBounds)
{
    var finalStrokeList = new List<InkStroke>(Strokes.Count);

    foreach (var stroke in Strokes)
    {
        var points = stroke.GetInkPoints();
        var finalPointList = new List<InkPoint>(points.Count);
        foreach (var point in points)
        {
            finalPointList.Add(MapPointToToSessionBounds(point, sessionBounds));
        }

        StrokeBuilder.SetDefaultDrawingAttributes(stroke.DrawingAttributes);
        var newStroke = StrokeBuilder.CreateStrokeFromInkPoints(finalPointList, stroke.PointTransform);
        finalStrokeList.Add(newStroke);
    }

    drawingSession.DrawInk(finalStrokeList);
}

Draw() - TextDrawble:

設置 Canvas 中文本的格式,使用文本和格式設置的 textLayout 來用於 drawingSession 的 DrawTextLayout 方法實現繪製;根據字體大小設置橫向偏移 HorizontalMarginBasedOnFont,固定的縱向偏移 verticalMargin;

public void Draw(CanvasDrawingSession drawingSession, Rect sessionBounds)
{
    const int verticalMargin = 3;
    CanvasTextFormat format = new CanvasTextFormat
    {
        FontSize = FontSize,
        WordWrapping = CanvasWordWrapping.NoWrap,
        FontWeight = IsBold ? FontWeights.Bold : FontWeights.Normal,
        FontStyle = IsItalic ? FontStyle.Italic : FontStyle.Normal
    };

    CanvasTextLayout textLayout = new CanvasTextLayout(drawingSession, Text, format, 0.0f, 0.0f);

    drawingSession.DrawTextLayout(textLayout, (float)(Bounds.X - sessionBounds.X + HorizontalMarginBasedOnFont), (float)(Bounds.Y - sessionBounds.Y + verticalMargin), TextColor);
} 

5. InfiniteCanvas

InfiniteCanvas 是主要邏輯處理,由 InfiniteCanvas.cs,InfiniteCanvas.Events.cs,InfiniteCanvas.TextBox.cs 三個部分類組成。

  • 其中 InfiniteCanvas.cs 這個類中主要是實現 OnApplyTemplate(),DependencyProperty 處理,控制項的定義,事件註冊,Canvas 的基礎事件處理等,InfiniteCanvas 中實現了一個 InkCanvas 所以可以實現各種筆觸的筆跡繪製;
  • InfiniteCanvas.Events.cs 主要是 Canvas 中的各種按鈕點擊等事件處理;
  • InfiniteCanvas.TextBox.cs 主要是 Canvas 中 TextBox 控制項對應的控制項定義和事件處理;

 

調用示例

InfiniteCanvas 控制項的調用非常簡單,下麵看看 XAML 中的調用:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">

  <Grid>
    <controls:InfiniteCanvas Name="canvas" IsToolbarVisible="True"/>
  </Grid>
</Page>

 

總結

到這裡我們就把 Windows Community Toolkit 3.0 中的 InfiniteCanvas 的源代碼實現過程講解完成了,希望能對大家更好的理解和使用這個功能有所幫助。InfiniteCanvas 控制項在繪畫類場景中有非常多的應用,控制項預設實現了多種筆觸的繪畫,橡皮,文字,redo undo 等重要功能,開發者也可以根據 InfiniteCanvas 的實現自定義 Toolbar 的樣式和更多的繪畫筆觸,不同的筆畫保存方式等。

最後,再跟大家安利一下 WindowsCommunityToolkit 的官方微博:https://weibo.com/u/6506046490大家可以通過微博關註最新動態。

衷心感謝 WindowsCommunityToolkit 的作者們傑出的工作,感謝每一位貢獻者,Thank you so much, ALL WindowsCommunityToolkit AUTHORS !!!


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

-Advertisement-
Play Games
更多相關文章
  • 由於需要在公司的內網進行神經網路建模試驗(https://www.cnblogs.com/NosenLiu/articles/9463886.html),為了更方便的在內網環境下快速的查閱資料,構建深度學習模型,我決定使用爬蟲來對深度學習框架keras的使用手冊進行爬取。 keras中文文檔的地址是 ...
  • 編程零基礎如何學習Python 如果你是零基礎,註意是零基礎,想入門編程的話,我推薦你學Python。雖然國內基本上是以C語言作為入門教學,但在麻省理工等國外大學都是以Python作為編程入門教學的。 那麼如何學習Python呢? 第一步:先把刀磨好 俗話說得好,磨刀不誤砍柴工,這個你不得不信,反正 ...
  • 在具備了volatile、CAS和模板方法設計模式的知識之後,我們可以來深入學習下AbstractQueuedSynchronizer(AQS),本文主要想從AQS的產生背景、設計和結構、源代碼實現及AQS應用這4個方面來學習下AQS,文章耗時一個月,所以篇幅有點長,需要一點耐心。 1、AQS產生背 ...
  • Size Balanced Tree 挺有意思的, 適合新手練習 ...
  • 事件是C#的基礎之一,學好事件對於瞭解.NET框架大有好處。 事件最常見的比喻就是訂閱,即,如果你訂閱了我的博客,那麼,當我發佈新博客的時候,你就會得到通知。 而這個過程就是事件,或者說是事件運行的軌跡。 事件是發散,以我的博客為核心,向所有訂閱者發送消息。我們把這種發散稱之為[多播]。 最常見的事 ...
  • 0.簡介 Abp 本身集成了一套許可權驗證體系,通過 ASP.NET Core 的過濾器與 Castle 的攔截器進行攔截請求,併進行許可權驗證。在 Abp 框架內部,許可權分為兩塊,一個是功能(Feature),一個是許可權項(Permission),在更多的時候兩者僅僅是概念不同而已,大體處理流程還是一 ...
  • v4.2.1 更新內容:1.重新定義數據轉發文本協議,使網關與ServerSuperIO以及之間能夠相關交互數據。2.擴展ServerSuperIO動態數據類的方法,更靈活。3.修複Designer增加轉發任務的一個BUG。4.修改數據轉發客戶端和服務端。5.增加硬體網關驅動。 v4.2.1 下載地 ...
  • C#中欄位、屬性和構造函數賦值的問題 提出問題 首先提出幾個問題: 1、如何實現自己的註入框架? 2、欄位和自動屬性的區別是什麼? 3、欄位和自動屬性聲明時的直接賦值和構造函數賦值有什麼區別? 4、為什麼只讀欄位和只讀自動屬性(只有get沒有set訪問器)都可以在構造函數中進行賦值? 5、反射可以給 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...