Quantcast
Channel: かずきのBlog@hatena
Viewing all articles
Browse latest Browse all 1387

ItemsControlの劣化版を自作してみる(DataTemplate対応コントロールの作成)

$
0
0

DataTemplateに対応したコントロールの作り方ということで、こちらのサイトを写経させていただきました。

カスタムコントロールの作成

カスタムコントロールを新規作成して、Generic.xamlに適当にStackPanelを追加します。ここにアイテムを追加していくっていう予定です。

<ResourceDictionaryxmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:WpfApplication4"><Style TargetType="{x:Type local:MyItemControl}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type local:MyItemControl}"><Border Background="{TemplateBinding Background}"BorderBrush="{TemplateBinding BorderBrush}"BorderThickness="{TemplateBinding BorderThickness}"><StackPanel x:Name="ItemsPanel" /></Border></ControlTemplate></Setter.Value></Setter></Style></ResourceDictionary>

依存プロパティの作成

今回は、データを格納するためのItemsSourceプロパティと、1要素1要素に適用するDataTemplateを設定するItemTemplateプロパティを追加します。

public IEnumerable ItemsSource
{
    get { return (IEnumerable)GetValue(ItemsSourceProperty); }
    set { SetValue(ItemsSourceProperty, value); }
}

// Using a DependencyProperty as the backing store for ItemsSource.  This enables animation, styling, binding, etc...publicstaticreadonly DependencyProperty ItemsSourceProperty =
    DependencyProperty.Register("ItemsSource", 
        typeof(IEnumerable), 
        typeof(MyItemControl), 
        new PropertyMetadata(null, ItemsSourceChanged));

public DataTemplate ItemTemplate
{
    get { return (DataTemplate)GetValue(ItemTemplateProperty); }
    set { SetValue(ItemTemplateProperty, value); }
}

// Using a DependencyProperty as the backing store for ItemTemplate.  This enables animation, styling, binding, etc...publicstaticreadonly DependencyProperty ItemTemplateProperty =
    DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(MyItemControl), new PropertyMetadata(null));

ItemsSourceは変更のタイミングで再描画したいので、変更時のコールバックを設定してます。

OnApplyTemplateとその他のメソッド

ということで、残りの部分です。ItemsSourceChangedは、再描画するためのメソッドを呼ぶだけのシンプル実装です。

privatestaticvoid ItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    ((MyItemControl)d).RenderItems();
}

ControlTemplateが適用されるタイミングで呼ばれるOnApplyTemplateメソッドも、Panelをテンプレートから取得するしたら再描画するだけです。

private Panel itemsPanel;

publicoverridevoid OnApplyTemplate()
{
    base.OnApplyTemplate();
    this.itemsPanel = this.GetTemplateChild("ItemsPanel") as Panel;
    this.RenderItems();
}

そして大事な再描画メソッドのRenderItemsメソッドです。こいつは、DataTemplateのLoadContentメソッドを使ってテンプレートからコントロールの実体を作成して、DataContextに要素をつっこんでからPanelに追加しています。

privatevoid RenderItems()
{
    if (this.itemsPanel == null)
    {
        return;
    }

    this.itemsPanel.Children.Clear();

    if (this.ItemsSource == null)
    {
        return;
    }

    foreach (var item inthis.ItemsSource)
    {
        var elm = this.ItemTemplate.LoadContent() as FrameworkElement;
        elm.DataContext = item;
        this.itemsPanel.Children.Add(elm);
    }
}

このメソッドが今回の核ですね。LoadContentメソッドメモメモ。

実行してみる

画面に適当においてみます。

<local:MyItemControl ItemsSource="{Binding}"><local:MyItemControl.ItemTemplate><DataTemplate><TextBlock Text="{Binding Name}" /></DataTemplate></local:MyItemControl.ItemTemplate></local:MyItemControl>

DataContextにはNameプロパティをもったオブジェクトの配列を入れてます。実行すると、こんな感じに表示されます。

f:id:okazuki:20140623211034j:plain


Viewing all articles
Browse latest Browse all 1387

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>