本文章是由機器翻譯。

UI 最前線

ItemsControl 的優缺點

Charles Petzold

下載程式碼範例

如果有人問我何種單一類別最 epitomizes 電源和彈性的 Windows Presentation Foundation (WPF) 和 Silverlight 我先說它 ’s 愚蠢的問題,然後,一下 ’s hesitation,沒有回應 「 DataTemplate 」。

一個 DataTemplate 基本上是視覺化樹狀結構的項目和控制項。程式設計人員使用 DataTemplates 給隱藏式 (Non-Visual 資料物件的視覺外觀。透過繫結屬性的視覺樹狀結構中的項目連結至資料物件的屬性。雖然 [DataTemplate 最常用來定義物件外觀的 ItemsControl] 或 [清單方塊 (其中一個類別衍生自 ItemsControl) 中,您也可以使用一個 DataTemplate 來定義一個 ContentControl 或一個 ContentControl] 衍生物如按鈕的內容的屬性來設定物件的外觀。

建立一個 DataTemplate — 或任何其他型別的例如 ControlTemplate 或 HierarchicalDataTemplate FrameworkTemplate 衍生物 — 是在幾個的 Silverlight 程式設計工作 can’t 完成在程式碼中的其中一個。您需要使用 XAML。它,一旦可能完全以程式碼使用架構-ElementFactory,建立 WPF 範本,但我認為我已實際發佈範例唯一的人 (11]、 [13] 和 [我的活頁簿的 16 的章節中 「 應用程式 = 程式碼 + 標記 」 [Microsoft 按,2006年]) 和技術現在已被取代。

我想在這份文件中顯示您是拖曳和放置的一種變化:使用者只會移動一個 ItemsControl 從項目至另一個。但我的主要目標是要實作一個完全流體外觀和感覺,似乎自然,及其中沒有任何突然 jerks 或消失的這整個程序。就說通常 painstakingly 方法 「 自然的外觀 」 是,並致力 fluidity 的任何程式,就必須避免洩露所有拙劣 machinations 只是表面的下方。

我使用我在上個月 ’s 專欄 (「 想到外部 [格線 」) 中顯示的技術的組合也共用的 DataTemplate 為兩個 ItemsControls 和一個 ContentControl — 這整個程式的基本概念。

程式版面配置

可下載的程式碼所附本文包含名為您可以從 [我的網站上執行, charlespetzold.com/silverlight/ItemsControlTransitions2 的 ItemsControlTransitions 單一 Silverlight 專案。(我解釋該 「 2 」 這個 URL 的結尾稍後)。您可以使用 WPF 程式在這個 Silverlight 程式中相同的概念。

這個程式會顯示兩個項目控制項,兩者都包含在 ScrollViewers。您可以視覺化左邊 ItemsControl 為銷售產生一個 「 市場 」。在右邊一個是您 「 購物籃 」。您可以使用滑鼠從市場中挑選產生的項目,並將它們移到購物籃。圖 1 顯示生成的項目,從市場的轉換至籃中。


圖 1 的 ItemsControlTransitions 顯示

雖然生成項目已移出的市場區隔,請注意中表示項目的來源會繼續在 ItemsControl 間距。如果拖曳的項目停留購物籃項目控制之前,使用者放開滑鼠按鈕,程式會回市場動畫項目。項目放到籃時,只會該間隔,再次關閉與動畫。根據位置放在項目動畫的間隔會開啟,會收到 「 的項目,和位置到動畫效果的項目是。

已移動項目,從市場,它不再存在那里,但是,’s 輕鬆地變更某程式詳細資料]。沒有設備存在籃中移除的項目,並將它傳回移到的市場區,但該功能或類似可以加入相當容易也。

圖 2 顯示 XAML 檔案的大量負責基本的版面配置。(遺失是兩個腳本與我稍後說明的七個動畫)。

圖 2 的 部分的 XAML 檔案負責的基本版面配置

<UserControl x:Class="ItemsControlTransitions.MainPage"   
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Name="this">
    <UserControl.Resources>
      <DataTemplate x:Key="produceDataTemplate">
        <Border Width="144"
          Height="144"
          BorderBrush="Black"
          BorderThickness="1"
          Background="AliceBlue"
          Margin="6">
          <Grid>
            <Grid.RowDefinitions>
              <RowDefinition Height="*" />
              <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>

            <Image Grid.Row="0"
              Source="{Binding Photo}" />
            <TextBlock Grid.Row="1"
              Text="{Binding Name}"
              HorizontalAlignment="Center" />
          </Grid>
        </Border>
      </DataTemplate>

        ...
        
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="White">
        <ScrollViewer HorizontalAlignment="Left"
          Margin="48">
            <ItemsControl Name="market"
              ItemTemplate="{StaticResource produceDataTemplate}"
                Width="156"
                MouseLeftButtonDown="OnMarketItemsControlMouseLeftButtonDown" />
        </ScrollViewer>

        <ScrollViewer HorizontalAlignment="Right"
          Margin="48">
            <ItemsControl Name="basket"
              ItemTemplate="{StaticResource produceDataTemplate}"
            Width="156" />
        </ScrollViewer>

        <Canvas Name="dragCanvas">
          <ContentControl Name="dragControl"
            ContentTemplate="{StaticResource produceDataTemplate}"
            Visibility="Collapsed" />
        </Canvas>
    </Grid>
</UserControl>

[資源] 區段會包含一個 DataTemplate 顯示產生] 項目,且此資源的參考設定為 ItemsTemplate 屬性的兩個 ItemsControls。

在就另外一個畫布涵蓋整個程式所佔用的區域。您自上個月 ’s 資料行記得如何使用 「 浮動 」 需要透過 UI 的其餘的主項目的畫布。此畫布的唯一的子系是 ContentControl,與也設定成該 DataTemplate 其 ContentTemplate。但是,因此這個 ContentControl 是一開始看不見 [可見性] 屬性設定為 Collapsed。

ContentControl 從衍生的控制項通常在 WPF 和 Silverlight 應用程式,但它 ’s 不通常是您會看到一個 ContentControl 本身。其實是如果您只想要顯示的物件,使用一個 DataTemplate,非常方便。以視覺方式,它 ’s 多非常類似的 ItemsControl 中的單一項目。

在程式開始所載入的一些產生較少的 XML 資料庫中 — 使用相同的檔案,從 ItemsControlPopouts 專案上個月 ’s 專欄中 — 然後再將其填滿的物件型別 ProduceItem ItemsControl 市場。這個類別有名稱] 和 [相片 [DataTemplate 來顯示每個項目所參考的屬性。

從 ItemsControl 提取的項目

市場區隔的 ItemsControl 已設定為 MouseLeftButtonDown 的處理常式。在這個事件的信的回條程式需要軍的 [ItemsControl 四牆範圍中的項目,並使其追蹤滑鼠。但 can’t 實際移除項目從 [ItemsControl 或間距會自動關閉。

如我所示範在上個月 ’s 專欄中,您可以存取 ItemContainerGenerator 屬性的一個 ItemsControl 取得可以將每個項目中的 ItemsControl 關聯產生以顯示該特定項目之視覺化樹狀結構的類別。此視覺樹狀結構中有型別 ContentPresenter 的根項目。

我的第一個 impulse 已套用一個 TranslateTransform ContentPresenter,而讓它浮動在 ItemsControl 外 RenderTransform 屬性。我知道從經驗,不過,這 doesn’t 完全運作。問題 isn’t 本身的 ItemsControl,問題在於 ScrollViewer 需要哪一個多媒體項目到其內部的子系。(相關資訊後面裁剪稍後解釋)。

而是,程式將按下的 ProduceItem 複製到 ContentControl,[ItemsControl 和定位在 ContentControl 精確地透過按下項目的 ContentPresenter。(程式可以取得 [相對於畫布 ContentPresenter 的位置使用永遠方便 TransformToVisual 方法)。您回收 XAML 檔案會將 [ContentControl 的 [可見性] 屬性設定為 [Collapsed,但現在程式切換看得見到該屬性。

在此同時在 [ItemsControl ContentPresenter 進行時不可見的。在 WPF,您可以執行這項只要設定可見性] 屬性為 [隱藏使項目不可見,但否則會導致項目 ’s 大小來觀察作為版面配置目的。[可見性] 屬性在 Silverlight doesn’t 有一個隱藏] 選項,如果您將 [ContentPresenter 的 [可見性] 屬性設定 Collapsed 間距會關閉最多。而是,您可以只將 Opacity 屬性設定為零],以模仿可見性設定為隱藏。項目仍然就有但 ’s 不可見。當您嘗試使用程式,您發現從在 [ItemsControl 項目轉換為可拖曳 ContentControl imperceptible。

在此時在 [ItemsControl ContentPresenter 顯示任何項目,但一個空的漏洞,並顯示此項目在 ContentControl 可以現在拖曳滑鼠,在螢幕上。

項目首

當我關於 Win16 和 Win32 API 撰寫書籍時, 我花整個章節說明如何使用捲軸來顯示更多的文字超過可容納那里一個視窗中。現在我們只要使用一個的 ScrollViewer 和每個人都得更快樂 — 我所有的大部分。

儘管在 WPF 和 Silverlight 配置其重要角色,[ScrollViewer 可以是有點棘手,有些時候使用。  它有可能會有點 puzzling,某些 peculiarities 和這個程式會顯示其中一個圖形。如果您可以預期的問題,請參閱。

我們會保留使用者移動滑鼠,在螢幕的產生項目。如果使用者可透過代表在購物籃的 ItemsControl 某處置放產生項目,它會成為該集合中的一部份。(多在此處理序在短時間內)。否則,程式動畫回到原始中 MainPage.xaml returnToOriginStoryboard 中使用兩個動畫項目。在動畫結束時,Opacity 屬性的 [ContentPresenter 設成 1]、 [ContentControl 的 [可見性] 屬性設定為 Collapsed,和拖曳事件會結束與所有項目返回到一般狀態。

若要判斷產生項目被放在 [[ItemsControl 上,程式會計算代表拖曳 ContentControl 的大小與位置的 Rect 物件和另一個代表 [ItemsControl 的大小與位置的 Rect 物件。在這兩個的情況下,程式會使用 TransformToVisual 方法取得控制項左上角的位置 — 點 (0,0) — 相對於頁面和 ActualWidth 和 ActualHeight] 屬性,以取得控制項 ’s 大小。Rect 結構 ’s 交集方法則會計算兩個矩形會非空白如果有 ’s 部份重疊的交集。

這正常運作除了 [ItemsControl 時已超過它所允許的垂直空間可容納更多的項目。ScrollViewer 然後開始到動作來讓其垂直捲軸可見,所以您可以捲動項目。但是,內 [ScrollViewer ItemsControl 真的認為本身為大於看到 ; 在一個非常真正的意義,ScrollViewer [ItemsControl 上提供只是可檢視視窗 (稱為 「 檢視區 」)。您永遠為該 ItemsControl 取得的位置和大小資訊指出完整大小 (稱為 「 範圍 」 大小) 和非檢視區大小。

這就是為什麼 ScrollViewer 需要多媒體及其子系。如果您被使用 Silverlight 的一段時間,可能為某些 laxity 特別習慣有關裁剪的子系。您幾乎都可以使用 RenderTransform 逸出從父 ’s 界限。但是,ScrollViewer 絕對需要多媒體項目或它只是 can’t 工作權限。

這表示 can’t 使用明顯的維度的 [ItemsControl 來決定有效的置放,因為在某些情況下,ItemsControl 延伸上方和下方 [ScrollViewer。該原因,我的程式決定有效的置放矩形,根據水平維度的 [ItemsControl — 因為它想要排除捲軸所佔用的區域 — 但 [ScrollViewer 的垂直的維度。

當 [ContentControl 放上 [ItemsControl 時,它可能會重疊兩個現有的項目,或只是一個如果它被放在頂端或底端項目,堆疊或不完全。我想要插入新的項目中最接近,它捨棄的列舉,ItemsControl 和其相關聯的 ContentPresenter 物件中的項目,並決定好的索引,要插入新的項目所需的特別色。(GetBasketDestinationIndex 方法是負責決定此索引)。項目會插入後,[ContentPresenter 相關聯的新項目提供的零的初始高度及的不透明度為 0,所以 isn’t 一開始看得見。

遵循此插入,程式啟始呼叫 transferToBasketStoryboard 含有五個動畫腳本:一個用來減少的市場區隔 ItemsControl 中不可見的 ContentPresenter 高度 ; 另增加新建立的購物籃 ItemsControl ; 和兩個多個以動畫顯示 Canvas.Left 和 Canvas.Top 中的不可見 ContentPresenter 高度附加在 ContentControl 回復位置的屬性。(我討論第五個動畫短時間內)。圖 3 顯示間距擴大為 [ContentControl 接近它的目的端。


圖 3 的動畫] 移到位置的新項目

動畫結束時, 新 ContentPresenter 給定的其中一個的不透明度和 [ContentControl 給定的 Collapsed 的可視性,現在我們 ’re 回到 ScrollViewers 內的兩個標準 ItemsControls 只處理。

[上] 和 [下] 問題

本文稍早我給予您該 URL charlespetzold.com/silverlight/ItemsControlTransitions2 試試程式。charlespetzold.com/silverlight/ItemsControlTransitions ,沒有 「 2 」 端從執行較早版本的程式。使用這個舊版移動數個透過產生的項目至籃 — 足以讓出現垂直的捲軸。現在將另一個拖曳,然後將它 straddling [ScrollViewer 底部。當您發行的滑鼠按鈕 [ContentControl 將向 [ItemsControl ’s 看不見,並突然消失的區域向下移動。項目已經正確插入,(如您可以向下捲動來驗證),但不是非常 elegantly。

現在捲動 [ScrollViewer,因此頂端的項目只是部分可見。  從購物籃移動其他的項目,並將其放置以便將插入的項目之前。新的項目投影成 ItemsControl,但不是 ’s 完全可見。不 ’s 相當當成 ItemsControl,底部問題的錯誤,但它還是需要一些說明。

此補充程式?若要以程式設計方式捲動 [ScrollViewer 某種方式是必要的。垂直捲動的目前作用中的一個 ScrollViewer 量是透過 VerticalOffset 屬性而提供的。這個數字是從整個 ItemsControl 頂端到頂端的 [ScrollViewer 顯示控制項的位置為正位移。

wouldn’t 是好只以動畫顯示該 VerticalOffset 屬性嗎?不幸的是,get 存取子是公用的。幸運的是,’s 可能以程式設計方式捲動 ScrollViewer,但您需要呼叫方法,稱為 ScrollToVerticalOffset。

若要完成這個小捲動工作,透過 Silverlight 動畫設備,我定義相依性屬性,名為 MainPage 本身的捲軸。在 XAML] 檔案中我給頁面的 「 這,」 的名稱,並定義 transferToBasketStoryboard 針對這個屬性中的第五個動畫:

<DoubleAnimation x:Name="scrollItemsControlAnima"
                 Storyboard.TargetName="this"
                 Storyboard.TargetProperty="Scroll" />

OnMouseLeftButtonUp 覆寫計算 [從] 和 [到此動畫的值。  (您可以比較這個額外的動畫效果標記為註解區塊程式碼開頭的註解 「 計算 ScrollViewer 捲動的動畫 」)。  此 [捲軸] 屬性以動畫方式,其屬性變更的處理常式會呼叫與動畫值 ScrollViewer ScrollToVerticalOffset 方法。

向流體的 UI

眾多多年前,電腦已非他們現在,會和螢幕上所發生的任何項目曾經是非常 startling 更慢。今天,程式可以實作完全變更其外觀的注意閃爍中的使用者介面。但是,就 ’s 也無法令人滿意。通常我們甚至 can’t 看到什麼的話,現在我們找到必要刻意 UI 變慢,並讓多個液體的轉換和自然會上。Silverlight 4 介紹我 ’m 想要討論,某些 「 流體 UI 」 功能,但即使是在 Silverlight 3 ’s 可能開始朝該方向的旅程。

Charles Petzold 是要 longtime 參與編輯器 MSDN Magazine*.*他目前正在寫入 「 程式設計 Windows 電話 7 數列,」 會為可用可下載 e-書籍的 2010年落在發行。 目前使用他的網站 charlespetzold.com 透過預覽版本。