背水一戰 Windows 10 (52) - 控制項(集合類): ItemsControl - 自定義 ItemsControl, 自定義 ContentPresenter

来源:http://www.cnblogs.com/webabcd/archive/2017/06/12/6991305.html
-Advertisement-
Play Games

背水一戰 Windows 10 之 控制項(集合類 - ItemsControl): 自定義 ItemsControl(自定義 GirdView 使其每個 item 占用不同大小的空間), 自定義 ContentPresenter 實現類似 GridViewItemPresenter 和 ListVi... ...


[源碼下載]


背水一戰 Windows 10 (52) - 控制項(集合類): ItemsControl - 自定義 ItemsControl, 自定義 ContentPresenter



作者:webabcd


介紹
背水一戰 Windows 10 之 控制項(集合類 - ItemsControl)

  • 自定義 ItemsControl(自定義 GirdView 使其每個 item 占用不同大小的空間)
  • 自定義 ContentPresenter 實現類似 GridViewItemPresenter 和 ListViewItemPresenter 的效果



示例
1、自定義 ItemsControl(自定義 GirdView 使其每個 item 占用不同大小的空間)
Controls/CollectionControl/ItemsControlDemo/MyItemsControlDemo.xaml

<Page
    x:Class="Windows10.Controls.CollectionControl.ItemsControlDemo.MyItemsControlDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Windows10.Controls.CollectionControl.ItemsControlDemo"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Page.Resources>
        <DataTemplate x:Key="ItemTemplate">
            <Grid Background="{Binding ColorValue}">
                <Grid Background="Black" VerticalAlignment="Top" Opacity="0.7">
                    <TextBlock Text="{Binding ColorName}" />
                </Grid>
            </Grid>
        </DataTemplate>
        <Style x:Key="ItemContainerStyle" TargetType="GridViewItem">
            <Setter Property="VerticalContentAlignment" Value="Stretch" />
            <Setter Property="HorizontalContentAlignment" Value="Stretch" />
            <Setter Property="Margin" Value="0" />
            <Setter Property="Padding" Value="0" />
        </Style>
        <ItemsPanelTemplate x:Key="ItemsPanel">
            <VariableSizedWrapGrid MaximumRowsOrColumns="8" Orientation="Horizontal" ItemWidth="100" ItemHeight="100"  />
        </ItemsPanelTemplate>

    </Page.Resources>

    <Grid Background="Transparent" Margin="10 0 10 10">
        <!--
            使用 MyGridView 控制項,其重寫了 GridView 的 PrepareContainerForItemOverride() 方法,詳見 MyGridView.cs
        -->
        <local:MyGridView x:Name="gridView" Width="812" VerticalAlignment="Top" HorizontalAlignment="Left"
                          ItemTemplate="{StaticResource ItemTemplate}"
                          ItemContainerStyle="{StaticResource ItemContainerStyle}"
                          ItemsPanel="{StaticResource ItemsPanel}" 
                          IsItemClickEnabled="False" 
                          SelectionMode="None">
        </local:MyGridView>
    </Grid>
</Page>

Controls/CollectionControl/ItemsControlDemo/MyItemsControlDemo.xaml.cs

/*
 * ItemsControl - 集合控制項(繼承自 Control, 請參見 /Controls/BaseControl/ControlDemo/)
 *     protected virtual void PrepareContainerForItemOverride(DependencyObject element, object item); - 為 item 準備 container 時
 *         element - item 的 container
 *         item - item
 *         
 * 
 * 本例用於演示如何使 GirdView 中的每個 item 占用不同大小的空間
 * 1、佈局控制項要使用 VariableSizedWrapGrid(利用其 RowSpan 和 ColumnSpan 來實現 item 占用不同大小的空間),需要註意的是其並非是虛擬化佈局控制項
 * 2、自定義 GridView,並重寫 ItemsControl 的 protected override void PrepareContainerForItemOverride(DependencyObject element, object item) 方法
 *    然後設置每個 item 的 VariableSizedWrapGrid.RowSpan 和 VariableSizedWrapGrid.ColumnSpan
 */

using System;
using System.Collections.Generic;
using System.Linq;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using System.Reflection;

namespace Windows10.Controls.CollectionControl.ItemsControlDemo
{
    public sealed partial class MyItemsControlDemo : Page
    {
        public MyItemsControlDemo()
        {
            this.InitializeComponent();
   
            BindData();
        }

        private void BindData()
        {
            Random random = new Random();

            // 獲取 Windows.UI.Colors 的全部數據
            Type type = typeof(Colors);
            List<ColorModel> colors = type.GetRuntimeProperties() // GetRuntimeProperties() 在 System.Reflection 命名空間下
                .Select(c => new ColorModel
                {
                    ColorName = c.Name,
                    ColorValue = new SolidColorBrush((Color)c.GetValue(null)),
                    ColSpan = random.Next(1, 3), // 此對象所占網格的列合併數
                    RowSpan = random.Next(1, 3) // 此對象所占網格的行合併數
                })
                .ToList();

            // 綁定數據
            gridView.ItemsSource = colors;
        }
    }


    /// <summary>
    /// 用於數據綁定的對象
    /// </summary>
    public class ColorModel
    {
        public string ColorName { get; set; }
        public SolidColorBrush ColorValue { get; set; }

        // 此對象所占的網格的列合併數
        public int ColSpan { get; set; }
        // 此對象所占的網格的行合併數
        public int RowSpan { get; set; }
    }


    /// <summary>
    /// 自定義 GridView,重寫 ItemsControl 的 protected override void PrepareContainerForItemOverride(DependencyObject element, object item) 方法
    /// 用於指定 GridView 的每個 item 所占網格的列合併數和行合併數
    /// </summary>
    public class MyGridView : GridView
    {
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            try
            {
                // 設置每個 item 的 VariableSizedWrapGrid.RowSpan 和 VariableSizedWrapGrid.ColumnSpan, 從而實現每個 item 占用不同大小的空間
                // 僅為演示用,由於這裡的 ColSpan 和 RowSpan 都是隨機計算的,所以可能會出現空白空間

                dynamic dynamicItem = item;
                element.SetValue(VariableSizedWrapGrid.ColumnSpanProperty, dynamicItem.ColSpan);
                element.SetValue(VariableSizedWrapGrid.RowSpanProperty, dynamicItem.RowSpan);
            }
            catch (Exception ex)
            {
                var ignore = ex;

                // 當有異常情況發生時(比如:item 沒有 ColSpan 屬性或 RowSpan 屬性)

                element.SetValue(VariableSizedWrapGrid.ColumnSpanProperty, 1);
                element.SetValue(VariableSizedWrapGrid.RowSpanProperty, 1);
            }
            finally
            {
                base.PrepareContainerForItemOverride(element, item);
            }
        }
    }
}


2、自定義 ContentPresenter 實現類似 GridViewItemPresenter 和 ListViewItemPresenter 的效果
Controls/CollectionControl/ItemsControlDemo/MyItemPresenter.cs

/*
 * 自定義 ContentPresenter 實現類似 GridViewItemPresenter 和 ListViewItemPresenter 的效果
 */

using System;
using Windows.Foundation;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Shapes;

namespace Windows10.Controls.CollectionControl.ItemsControlDemo
{
    class MyItemPresenter : ContentPresenter
    {
        Panel _container = null; // item 的容器(即在 DataTemplate 中定義的根元素,在示例 MyItemPresenterDemo.xaml 中用的是 Grid)
        Rectangle _pointerOverBorder = null; // 滑鼠經過 item 時覆蓋在 item 上的 rectangle
        Rectangle _focusVisual = null; // 選中 item 時覆蓋在 item 上的 rectangle

        Storyboard _pointerDownStoryboard = null; // 滑鼠按下時的動畫
        Storyboard _pointerUpStoryboard = null; // 滑鼠抬起時的動畫

        public MyItemPresenter()
            : base()
        {
            base.Margin = new Thickness(10);
        }

        // override OnApplyTemplate() - 應用控制項模板時調用
        protected override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            _container = (Panel)VisualTreeHelper.GetChild(this, 0);
        }

        // override GoToElementStateCore() - VisualState 轉換時調用(此方法僅在自定義 ContentPresenter 並將其應用於 GridView 或 ListView 的 ItemContainerStyle 時才會被調用)
        //     stateName - VisualState 的名字
        //     useTransitions - 是否使用 VisualTransition 過渡效果
        protected override bool GoToElementStateCore(string stateName, bool useTransitions)
        {
            base.GoToElementStateCore(stateName, useTransitions);

            switch (stateName)
            {
                // 正常狀態
                case "Normal":
                    HidePointerOverVisuals();
                    HideFocusVisuals();
                    if (useTransitions)
                    {
                        StopPointerDownAnimation();
                    }
                    break;

                // 選中狀態
                case "Selected":
                case "PointerFocused":
                    ShowFocusVisuals();
                    if (useTransitions)
                    {
                        StopPointerDownAnimation();
                    }
                    break;

                // 取消選中狀態
                case "Unfocused":
                    HideFocusVisuals();
                    break;

                // 滑鼠經過狀態
                case "PointerOver":
                    ShowPointerOverVisuals();
                    if (useTransitions)
                    {
                        StopPointerDownAnimation();
                    }
                    break;

                // 滑鼠點擊狀態
                case "Pressed":
                case "PressedSelected":
                    if (useTransitions)
                    {
                        StartPointerDownAnimation();
                    }
                    break;

                default: break;
            }

            return true;
        }

        private void StartPointerDownAnimation()
        {
            if (_pointerDownStoryboard == null)
                CreatePointerDownStoryboard();

            _pointerDownStoryboard.Begin();
        }

        private void StopPointerDownAnimation()
        {
            if (_pointerUpStoryboard == null)
                CreatePointerUpStoryboard();

            _pointerUpStoryboard.Begin();
        }

        private void ShowFocusVisuals()
        {
            if (!FocusElementsAreCreated())
                CreateFocusElements();

            _focusVisual.Opacity = 1;
        }

        private void HideFocusVisuals()
        {
            if (FocusElementsAreCreated())
                _focusVisual.Opacity = 0;
        }

        private void ShowPointerOverVisuals()
        {
            if (!PointerOverElementsAreCreated())
                CreatePointerOverElements();

            _pointerOverBorder.Opacity = 1;
        }

        private void HidePointerOverVisuals()
        {
            if (PointerOverElementsAreCreated())
                _pointerOverBorder.Opacity = 0;
        }

        private void CreatePointerDownStoryboard()
        {
            /*
             * 用這種方式為 item 實現滑鼠按下的效果會報錯(Attempted to read or write protected memory. This is often an indication that other memory is corrupt.),不知道為什麼
             * PointerDownThemeAnimation pointerDownAnimation = new PointerDownThemeAnimation();
             * Storyboard.SetTarget(pointerDownAnimation, _container);
             * Storyboard pointerDownStoryboard = new Storyboard();
             * pointerDownStoryboard.Children.Add(pointerDownAnimation);
             */

            DoubleAnimation da1 = new DoubleAnimation()
            {
                To = 0.9,
                Duration = TimeSpan.FromMilliseconds(100)
            };
            DoubleAnimation da2 = new DoubleAnimation()
            {
                To = 0.9,
                Duration = TimeSpan.FromMilliseconds(100)
            };
            Storyboard.SetTarget(da1, _container);
            Storyboard.SetTargetProperty(da1, "(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)");
            Storyboard.SetTarget(da2, _container);
            Storyboard.SetTargetProperty(da2, "(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)");
            if (!(_container.RenderTransform is TransformGroup))
            {
                TransformGroup Group = new TransformGroup();
                Group.Children.Add(new ScaleTransform());
                _container.RenderTransform = Group;
                _container.RenderTransformOrigin = new Point(0.5, 0.5);
            }

            _pointerDownStoryboard = new Storyboard();
            _pointerDownStoryboard.Children.Add(da1);
            _pointerDownStoryboard.Children.Add(da2);
            _pointerDownStoryboard.Begin();
        }

        private void CreatePointerUpStoryboard()
        {
            DoubleAnimation da1 = new DoubleAnimation()
            {
                To = 1,
                Duration = TimeSpan.FromMilliseconds(100)
            };
            DoubleAnimation da2 = new DoubleAnimation()
            {
                To = 1,
                Duration = TimeSpan.FromMilliseconds(100)
            };
            Storyboard.SetTarget(da1, _container);
            Storyboard.SetTargetProperty(da1, "(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)");
            Storyboard.SetTarget(da2, _container);
            Storyboard.SetTargetProperty(da2, "(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)");
            if (!(_container.RenderTransform is TransformGroup))
            {
                TransformGroup Group = new TransformGroup();
                Group.Children.Add(new ScaleTransform());
                _container.RenderTransform = Group;
                _container.RenderTransformOrigin = new Point(0.5, 0.5);
            }

            _pointerUpStoryboard = new Storyboard();
            _pointerUpStoryboard.Children.Add(da1);
            _pointerUpStoryboard.Children.Add(da2);
            _pointerUpStoryboard.Begin();
        }

        private void CreatePointerOverElements()
        {
            _pointerOverBorder = new Rectangle();
            _pointerOverBorder.IsHitTestVisible = false;
            _pointerOverBorder.Opacity = 0;
            // 這裡把顏色寫死了,僅為演示用,實際寫的時候要摘出來寫成依賴屬性
            _pointerOverBorder.Fill = new SolidColorBrush(Color.FromArgb(0x50, 0x50, 0x50, 0x50));

            _container.Children.Insert(_container.Children.Count, _pointerOverBorder);
        }

        private void CreateFocusElements()
        {
            _focusVisual = new Rectangle();
            _focusVisual.IsHitTestVisible = false;
            _focusVisual.Height = 10;
            _focusVisual.VerticalAlignment = VerticalAlignment.Bottom;
            // 這裡把顏色寫死了,僅為演示用,實際寫的時候要摘出來寫成依賴屬性
            _focusVisual.Fill = new SolidColorBrush(Color.FromArgb(0xff, 0xff, 0x0, 0x0));

            _container.Children.Insert(0, _focusVisual);
        }

        private bool FocusElementsAreCreated()
        {
            return _focusVisual != null;
        }

        private bool PointerOverElementsAreCreated()
        {
            return _pointerOverBorder != null;
        }
    }
}

Controls/CollectionControl/ItemsControlDemo/MyItemPresenterDemo.xaml

<Page
    x:Class="Windows10.Controls.CollectionControl.ItemsControlDemo.MyItemPresenterDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Windows10.Controls.CollectionControl.ItemsControlDemo"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Page.Resources>
        <Style x:Key="MyGridViewItemPresenterTemplate" TargetType="GridViewItem">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="GridViewItem">
                        <!--
                            自定義 ContentPresenter 實現類似 GridViewItemPresenter 和 ListViewItemPresenter 的效果
                        -->
                        <local:MyItemPresenter />
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Page.Resources>

    <Grid Background="Transparent">
        <GridView x:Name="gridView" SelectionMode="Single" Margin="10 0 10 10" 
                  ItemContainerStyle="{StaticResource MyGridViewItemPresenterTemplate}">
            <GridView.ItemTemplate>
                <DataTemplate>
                    <Grid Height="100" Width="100" Background="Blue">
                        <TextBlock x:Name="lblName" Text="{Binding Name}" Foreground="Yellow" />
                    </Grid>
                </DataTemplate>
            </GridView.ItemTemplate>
        </GridView>
    </Grid>
</Page>

Controls/CollectionControl/ItemsControlDemo/MyItemPresenterDemo.xaml.cs

/*
 * 本例用於演示如何自定義 ContentPresenter 實現類似 GridViewItemPresenter 和 ListViewItemPresenter 的效果
 */

using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
using Windows10.Common;

namespace Windows10.Controls.CollectionControl.ItemsControlDemo
{
    public sealed partial class MyItemPresenterDemo : Page
    {
        public MyItemPresenterDemo()
        {
            this.InitializeComponent();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            gridView.ItemsSource = TestData.GetEmployees();
        }
    }
}



OK
[源碼下載]


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

-Advertisement-
Play Games
更多相關文章
  • 1,值類型對象有兩種表示形式:未裝箱和已裝箱,相反引用類型總是處於已裝箱形式 2,值類型從System.ValueType派生。該類型提供了與System.Object相同的方法。但是System.ValueType重寫了Equals方法,能在兩個對象的欄位值完全匹配的前提下返回true。此外,Sy ...
  • 代碼格式化:Ctrl K +Ctrl D ...
  • 寫在前面整個項目都托管在了 Github 上:https://github.com/ikesnowy/Algorithms-4th-Edition-in-Csharp善用 Ctrl + F 查找題目。本節你可能會需要的兩個測試數據文件:largeW: http://algs4.cs.princeto... ...
  • ServerSuperIO以前所做的工作逐步為形成迴路控制或級聯控制打下基礎,例如:服務連接器和設備驅動連接器的開發與應用。總之,是通過多種形式下發命令控制設備(驅動)或感測器,雲端控制站點或監測點的感測器、App或者其他終端控制感測器、根據感測器的採集數據控制另一個感測器等。 ...
  • 現在辦公要流程化,營銷也有流程,流程現在已經是各種生活活動不可缺少的一部分了。就像這句耳熟能詳的話:“凡事,我們先走個流程嘛!”,在信息化、流程化的背景下。工作流引擎,這個名詞就出現了!那麼,什麼是工作流引擎呢?所謂工作流引擎是指workflow作為應用系統的一部分,併為之提供對各應用系統有決定作用 ...
  • 前段時間巨硬發佈了一款新的輸入設備Surface Dial,配合Surface Studio使用簡直炫酷到沒朋友。 本人由於公司業務有幸參與了微軟的相關培訓,最大的收穫覺得是發現WPF居然也可以開發Dial, WPF居然可以使用UWP的API! 不賣關子,關鍵就是名為“UwpDesktop”的一個N ...
  • Object中的公共方法解釋: 公共方法: Equals: public class Object { public virtual Boolean Equals(Object obj) { //如果兩個引用指向同一個對象,他們肯定包含相同的值 if (this == obj) return tru ...
  • 由於種種原因吧,我需要使用一個WPF程式起調一個UWP程式,下麵總結一下,給自己個備份。 啟動UWP程式的關鍵是協議啟動 給我們的UWP應用添加一個協議,like this: 然後使用協議啟動該UWP有一下幾種方式: 1. 使用UWP的Launcher API // Create the URI t ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...