2013年1月23日水曜日

依存関係プロパティ(その1)


依存関係プロパティ(DependecyProperty)について

依存関係プロパティは、「ほかの要素の値に依存してプロパティの値を決定する機構」
    以下にDependencyPropertyの取得方法(5つ方式)を示す

1.直接取得
    > [System.Windows.Controls.Control]::FontSizeProperty
    ( これでも同じ、 [System.Windows.Controls.Button]::FontSizeProperty)

                       ↓↓↓(同じものが見える)

  Name FontSize
  PropertyType System.Double
  OwnerType System.Windows.Documents.TextElement
  DefaultMetadata System.Windows.FrameworkPropertyMetadata
  ValidateValueCallback System.Windows.ValidateValueCallback
  GlobalIndex 21
  ReadOnly False

    > [System.Windows.Controls.Control]::FontSizeProperty
                   ↓↓↓(リターン)
        System.Windows.DependencyProperty

        「C#」的な定義は以下の通り
        > public static readonly DependencyProperty FontSizeProperty;


2.DependencyObjectクラスのメソッドで取得

    > [System.Windows.DependencyObject]::GetLocalValueEnumerator()
               ↓↓↓(リターン)
        System.Windows.LocalValueEnumerator

        すなわち、[System.Windows.LocalValueEntry]型として以下の
        4種のデータの配列が得られる

            ・WPF明示的に設定したDependencyProperty
            ・WPF明示的設定なAttached Property(区別つかず)
            ・WFP暗示的に設定されたDependencyProperty
            ・Xamlにより設定されたDependencyProperty

        得られないもの  ←  どうやってみるかは、別記事で…
           ・「CLR」なDependencyPropertyは見えない
           ・「inherit」なDependencyPropertyは見えない
               
        ちなみに、依存関係プロパティ・インスタンスからは、以下様にたどれる。
> [System.Windows.DependencyObject]::GetValue(System.Windows.DependencyProperty)
                       ↓↓↓(リターン)
                  System.Object
3.MarkupWriterクラスのメソッドで取得

> [System.Windows.Markup.Primitives.MarkupWriter]::GetMarkupObjectFor(System.Object)
            ↓↓↓(リターン)
       System.Windows.Markup.Primitives.MarkupObject

  得られたインスタンスを以下のように表示すると、
> [System.Windows.Markup.Primitives.ElementMarkupObject]::Properties

            以下のものが見える
            ・WPF明示的に設定したDependencyProperty
            ・WPF明示的設定なAttached Property(区別がつく)
            ・「CLR」なProperty

            得られないもの ← どうやってみるかは、別記事で…
            ・WFP暗示的に設定されたDependencyProperty
            ・Xamlにより設定されたDependencyProperty
            ・「inherit」なDependencyPropertyは見えない

4.DependencyPropertyDescriptorクラスのメソッドで取得

> [System.ComponentModel.DependencyPropertyDescriptor]::FromName(`
                                                  System.String, System.Type, System.Type)
                                                               ①                    ②                  ③
            ①DP名        文字列
            ②Owner型   DPをRegisterしたクラス型
            ③Target型   DPを参照するクラス型

                   ↓↓↓(リターン)
           System.ComponentModel.DependencyPropertyDescriptor

5.PresentationFrameworkアセンブリから一覧を得る

    以下で型の全一覧を取得し、そこからDPをすべて抽出する
    >   add-type -assembly PresentationFramework -PassThru |                                
    >   % { $_.GetFields() } |                                                              
    >   % { foreach ( $f in $_ ) { if ($f.FieldType.Name -eq "DependencyProperty") { $f } } } |
    >   ? { $_.name -ne "Property" } |                                                      
    >   % { $_.GetValue("") } |                                                              
    >   sort GlobalIndex |                                                                  
    >   get-unique                                                                          


依存関係プロパティを総合的に表示するツールを作ってみた。
    ツールの中身は、このブログの目的とは違うので省略

        利用結果の例
       > $form.findname("Button2") | dp2:
  Name DP Type Value base
  ============ ======== === ====
  IsMouseDirectlyOver Indirect,Xaml False Local
  IsKeyboardFocused Indirect,Xaml False Local
  Content WPF Direct Button2 Local
  IsMouseCaptured Indirect,Xaml False Local
  Name WPF Direct Button2 Local
  HasContent Indirect,Xaml True Local

実際動かして確認してみる。
PowershellだけでWPF表示(Powershell3.0でも2.0でも稼働)
.Netframeworkは3.0以上が必要
WPFの約束としてPowershellはSTAモードで動く必要あり
以下コードを
  ①Powershellコンソールにコピペして実行
  ②ISEで実行する時はすでにSTAモードなので適時修正して実行
    注意:ブラウザによってはコピペで行頭に余分な空白が出来てしまうことあり
           C:\temp> □'@   ← ここの行の行頭に空白あると動かない

image 
 

#-----------------------------------
if ($host.Version.Major -eq 3) {
     powershell.exe
} else {
     powershell.exe -version 2 -sta
}

$xaml = @'
<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="InheritFont.Window1" Height="225" Width="180">

    <GroupBox FontWeight="Bold" Name="myGroupBox">
        <GroupBox.Header>
            Buttons
        </GroupBox.Header>
        <StackPanel>
            <Button Name="Button1" FontWeight="Medium">Button 1</Button>
            <Button Name="Button2">Button 2</Button>
            <Button Name="Button3" FontWeight="Normal">Button 3</Button>
        </StackPanel>
    </GroupBox>

</Window>
'@

$code = @'
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace MyButton
{
    public class EventTest
    {
        public GroupBox gb;

        public void subscribe(Button b)
        {
            b.Click += Button_Click1;
        }

        public void Button_Click1(object sender, RoutedEventArgs e)
        {
            if (gb.FontWeight == FontWeights.Normal)
            {
                gb.FontWeight = FontWeights.Bold;
            } else {
                gb.FontWeight = FontWeights.Normal;
            }
        }
    }
}
'@

if ($host.Version.Major -eq 3) {
    Add-Type $code -ReferencedAssemblies @("WindowsBase","PresentationCore","PresentationFramework","System.Xaml","System.xml")
} else {
    Add-Type $code -ReferencedAssemblies @("WindowsBase","PresentationCore","PresentationFramework")
}
$form = [System.Windows.Markup.XamlReader]::Parse($xaml)
$mb = New-Object MyButton.EventTest
$mb.gb = $form.findname("myGroupBox")
$mb.subscribe($form.findname("Button3"))
[void]$Form.ShowDialog()

 

 
1.直接取得

  > [System.Windows.Controls.Control]::FontWeightProperty
    (これでも同じ [System.Windows.Controls.Button]::FontWeightProperty)
                     ↓↓↓
    Name                         : FontWeight
    PropertyType              : System.Windows.FontWeight
    OwnerType                : System.Windows.Documents.TextElement
    DefaultMetadata         : System.Windows.FrameworkPropertyMetadata
    ValidateValueCallback :
    GlobalIndex               : 154
    ReadOnly                  : False

2.DependencyObjectクラスのメソッドで取得

  > $form.FindName("Button2").GetLocalValueEnumerator()

     Property                  Value
     --------                    -----
     Name                      Button2
     IsMouseDirectlyOver False
     IsMouseCaptured     False
     IsKeyboardFocused  False
     Content                  Button 2
     HasContent             True

3.MarkupWriterクラスのメソッドで取得

> [System.Windows.Markup.Primitives.MarkupWriter]::GetMarkupObjectFor($form.FindName("Button2")).Properties

            ↓↓↓(以下の2つ)
       ①DependencyProperty    : Content
       ②DependencyProperty    : Name

4.DependencyPropertyDescriptorクラスのメソッドを使って取得

> [System.ComponentModel.DependencyPropertyDescriptor]::FromName("FontWeight", [System.Windows.Controls.Button], [System.Windows.FrameworkElement] )
               ↓↓↓(以下のものが得られる)
    DependencyProperty          : FontWeight

5.PresentationFrameworkアセンブリから一覧を得る
     面倒なので省略

0 件のコメント:

コメントを投稿