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

UWPでBindingのAncestorTypeを指定したい

$
0
0

出来ません。

なので疑似的にやるBehaviorを作ってみました。以下のような感じです。

using Microsoft.Xaml.Interactivity;
using System;
using System.Reflection;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;

namespace App28
{
    publicclass AncestorBindingBehavior : DependencyObject, IBehavior
    {
        /// <summary>/// Binding対象のオブジェクト/// </summary>public DependencyObject AssociatedObject { get; set; }

        /// <summary>/// Binding/// </summary>public Binding Binding { get; set; }

        /// <summary>/// 親方向に遡って探したい型の名前/// </summary>publicstring AncestorType { get; set; }

        /// <summary>/// Binding対象のプロパティ名/// </summary>publicstring TargetPropertyName { get; set; }

        publicvoid Attach(DependencyObject associatedObject)
        {
            this.AssociatedObject = associatedObject;
            // プロパティの設定が未完全の場合は何もしないif (this.Binding == null || string.IsNullOrWhiteSpace(this.TargetPropertyName) || string.IsNullOrWhiteSpace(this.AncestorType)) { return; }
            // VisualTree構築後に1度だけ実行する
            ((FrameworkElement)this.AssociatedObject).Loaded += this.AncestorBindingBehavior_Loaded;
        }

        privatevoid AncestorBindingBehavior_Loaded(object sender, RoutedEventArgs e)
        {
            // イベント解除
            ((FrameworkElement)this.AssociatedObject).Loaded -= this.AncestorBindingBehavior_Loaded;

            // 親を遡ってソースとなるオブジェクトを探す
            var source = FindAncestorType(this.AssociatedObject, this.AncestorType);
            // バインドする添付プロパティを探す
            var targetProperty = GetDependencyProperty(this.AssociatedObject.GetType(), this.TargetPropertyName);
            // 失敗したら何もしないif (source == null || targetProperty == null) { return; }
            // Bindingのソースをセットしてプロパティにバインドするthis.Binding.Source = source;
            ((FrameworkElement)this.AssociatedObject).SetBinding(targetProperty,
                this.Binding);
        }

        publicvoid Detach()
        {
        }

        /// <summary>/// VisualTreeを親へ辿っていって指定した型名のものがあったら返す/// </summary>/// <paramname="element"></param>/// <paramname="type"></param>/// <returns></returns>privatestatic DependencyObject FindAncestorType(DependencyObject element, string type)
        {
            if (element.GetType().Name == type) { return element; }

            var parent = VisualTreeHelper.GetParent(element);
            if (parent == null) { returnnull; }
            return FindAncestorType(parent, type);
        }

        /// <summary>/// 継承関係を親へ辿っていきながら指定した添付プロパティが定義されてたらそれを返す/// </summary>/// <paramname="type"></param>/// <paramname="propertyName"></param>/// <returns></returns>privatestatic DependencyProperty GetDependencyProperty(Type type, string propertyName)
        {
            var field = type
                .GetTypeInfo()
                .GetDeclaredField($"{propertyName}Property");
            if (field != null)
            {
                return (DependencyProperty) field.GetValue(null);
            }

            var property = type
                .GetTypeInfo()
                .GetDeclaredProperty($"{propertyName}Property");
            if (property != null)
            {
                return (DependencyProperty) property.GetValue(null);
            }

            var baseType = type.GetTypeInfo().BaseType;
            if (baseType == typeof(object)) { returnnull; }

            return GetDependencyProperty(baseType, propertyName);
        }
    }
}

使い方は簡単。バインド対象にぽとっとBehaviorを落として各種プロパティを設定するだけ。 ButtonのVisibilityと、ListViewItemのIsSelectedをバインドするには以下のように使います。

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"      xmlns:local="using:App28"      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"      xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"      x:Class="App28.MainPage"      mc:Ignorable="d">
    <Page.Resources>
        <local:BooleanToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter"
                                            IsInverse="True"/>
    </Page.Resources>
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <ListView ItemsSource="{x:Bind Users}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <TextBlock Text="{Binding}" />
                        <Button Content="削除">
                            <Interactivity:Interaction.Behaviors>
                                <!-- ここ! -->
                                <local:AncestorBindingBehavior AncestorType="ListViewItem"
                                                               TargetPropertyName="Visibility"
                                                               Binding="{Binding IsSelected, Mode=TwoWay, Converter={StaticResource InverseBooleanToVisibilityConverter}}" />
                            </Interactivity:Interaction.Behaviors>
                        </Button>
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Page>

Viewing all articles
Browse latest Browse all 1387

Trending Articles



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