WPF中的圖資料表設計工具 – 4 (譯)

來源:互聯網
上載者:User
文章目錄
  • Save
  • Open
  • Copy, Paste, Delete, Cut
  • Align, Distribute
  • Order

[原文地址] http://www.codeproject.com/KB/WPF/WPFDiagramDesigner_Part4.aspx
[原文作者] sukram

  • Part 1 - 在Canvas中移動、縮放或者旋轉任何類型的對象
  • Part 2 - Toolbox, drag & drop, rubberband selection
  • Part 3 - Connecting items
介紹

在這篇文章中,我添加下面的命令:

  • Open, Save
  • Cut, Copy, Paste, Delete
  • Print
  • Group, Ungroup
  • Align (Left, Right, Top, Bottom, Centered horizontal, Centered vertical)
  • Distribute (horizontal, vertical)
  • Order (Bring forward, Bring to top, Send backward, Send to back)

   注意:我將僅僅支援.NET 3.5平台下面的Visual Studio 8.0!

命令

   我將直接使用WPF命令,就像在WPF SDK文檔中描述一樣,無需額外的基礎設施。

分組

   我的第一個分組的方法是將一個DesignerItem對象作為一個分組的容器使用。因此,建立一個DesignerItem類的新執行個體對象,這個執行個體對象的content是一個Canvas對象。在這個canvas中,我計劃放置進行分組的DesignerItem。不過,在我把item放在用於分組的canvas上之前,我必須從DesignerCanvas移除他們,這因為WPF中的元素不能同時是兩個元素的子項目。否者,如果您去嘗試,您將得到InvalidOperationException異常,並收到下面的異常訊息:

"Specified element is already the logical child of another element. 
Disconnect it first."

   所以,我們從DesignerCanvas上移除Item ,然後將它添加到GroupCanvas上。現在有趣的是理解WPF幕後所做的工作:當我從畫布上移除的Item時,Item的模板被卸下,當我把它添加到GroupCanvas上時,一個新的模板又會被載入。現在,你還記得上一篇文章中我如何串連DesignerItems會的嗎?在那裡,我通過Connector去實現串連Item,Connector是被串連的DesignerItem的模板的一部分。一旦我們從DesignerCanvas刪除Item,它的模版也將消失。你看到問題嗎?我是通過他們的模板串連DesignerItem的,所以DesignerItem本身根本沒有存在有關Connection的資訊。所有Connection的相關資訊是與DesignerItem的模板孤立的。

    想象一下,一個資料庫圖表中,DesignerItem的content是一個資料庫表。該表將永遠不會認可與其他表的關係。一個解決辦法是建立一個資訊隧道,資訊從DesignerItem的模板傳到DesignerItem,再傳到table。 更好的解決辦法是重新設計應用程式和劃整為零,如劃分為:

 

  • Template (view)
  • Designer item (view model)
  • Database table (model)

     

       我在這篇文章中間將不會重新設計代碼。相反,直到文章的結尾,我將使用'view-only-approach'。使用越難,好的解決方案就越有希望。(我將會在以後的文章中涉及一些支援模型設計的文章)。

       所以讓我們繼續,另外一種對DesignerItem分組方法,是使用下面的介面:

    public interface IGroupable
    {
    Guid ID { get; }
    Guid ParentID { get; set; }
    bool IsGroup { get; set; }
    }

     

       這個觀點是用已經實現了IGroupable介面的DesignerItem類,成為分組結構的一部分。它如下工作:

    • 建立一個新的DesignerItem對象,它有一個唯一的ID和一個設定為true的IsGroup屬性。
    • 對於每一個群組成員,設定他的ParentID為父親group的ID。

       這個非常簡單,當真正地修改Item(Select, Move, Resize, Copy, ...)的時候,它才真正的起作用。對於每個操作,我們都要考慮item的分組的狀態,聽起來有很多工作要做。但是使用了ling,就沒那麼難了。因此,我們將大部分工作放在SelectionService中去實現。

       注意:Connection類沒有實現IGroupable介面。所以它不是分組的直接部分。但間接地:一個connection 總是附加到一個item上。這使我可以靈活地重連/串連item。無論他們是否是一個分組的成員。

    Save

       為了儲存一個圖表,我選擇使用XML和XAML的組合。對於DesignerItem相關的資料,我使用XML,content將序列化為XAML。在這裡,請注意序列化DesignerItem的content為XAML僅僅保留視覺效果。因此,這是短期內唯一的解決辦法。要建立XML檔案,我使用LINQ。由於這是我第一次使用LINQ來做,使用它不要指望它是必要的“正確”的方法。

       下面是一個例子,我是如何序列DesignerItem: 

     XElement serializedItems = new XElement("DesignerItems",
                              from item in designerItems
                              let contentXaml = XamlWriter.Save(((DesignerItem)item).Content)
                              select new XElement("DesignerItem",
                                          new XElement("Left", Canvas.GetLeft(item)),
                                          new XElement("Top", Canvas.GetTop(item)),
                                          new XElement("Width", item.Width),
                                          new XElement("Height", item.Height),
                                          new XElement("ID", item.ID),
                                          new XElement("zIndex", Canvas.GetZIndex(item)),
                                          new XElement("IsGroup", item.IsGroup),
                                          new XElement("ParentID", item.ParentID),
                                          new XElement("Content", contentXaml)
                                          )
                               );

      
  •     在讓關鍵字允許您在一個變數中儲存在一個子運算式的結果,這個變數可以在隨後的運算式中使用。在這裡,我使用此功能將序列化的content儲存在contentXaml變數,我用下面幾行代碼。最後,我將使用XElement類的Save方法來儲存基本XML樹:

     

     XElement.Save(fileName)

    Open

        當我們從XML檔案載入一個圖表的時候,我們必須從載入DesignerItem開始,因為我們需要他們的connector來建立connection。我們瞭解到,connector是該item模板的一部分。在我們繼續以前,DesignerItem必須載入他的模板。幸運的是,控制項的類提供了一個ApplyTemplate()方法。它強迫WPF布局系統載入控制項範本,以便它的部分能被引用。

        在前面的一篇文章中,我提供一個自訂ConnectorDecorator模板的機制,它允許你在DesignerItem的周圍自由地放置connector 。這種解決辦法,在DesignerItem的Loaded事件之後, 應用自訂模板。該DesignerItem在螢幕上可見之前,而不會激發該事件。在該命令已經結束之前,螢幕不能重繪。因此,唯一的方法是將在開啟命令中明確設定ConnectorDecorator自訂模板,看到SetConnectorDecoratorTemplate(item)的方法。

     注意:當定義定製的connector時,必須設定的x:Name屬性。一個connection使用名字來確定其來源和接收的connector。

     

     <s:Connector x:Name="Left" Orientation="Left" 
        VerticalAlignment="Center" HorizontalAlignment="Left"/>

     

    Copy, Paste, Delete, Cut

       複製和粘貼命令的工作類似於開啟和儲存命令,但它們只適用於所選的item ,他們讀寫序列化的content到剪貼簿。 刪除命令只是從designer canvas所有的子集中刪除選定item,最後剪下命令是一個複製和刪除命令的組合。

    Align, Distribute

       這些命令,沒有太多的話要說,首先,除了在Align中第一個被選中的item是參考item (也稱為主選擇item)。這僅僅當你使用 LeftMouseButton + Ctrl, 或者LeftMouseButton + Shift選擇item,而不是你去用rubberband選擇。

    Order

       這個Panel類提供了一個名字為ZIndex的附加的的屬性。它定義了z-plane子項目的顯示的順序。所以我們只需要更改該屬性將item向前或向後。

         WPF中的圖資料表設計工具一共有四篇文章,前面三篇已經由WizRay翻譯,你也可以在我的部落格上找到,這是第四篇。希望這些對想實現自己WPF流程設計器和表單設計器的朋友有所協助。(紅色譯者注)

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.