ラベル 依存関係プロパティ の投稿を表示しています。 すべての投稿を表示
ラベル 依存関係プロパティ の投稿を表示しています。 すべての投稿を表示

2013年1月27日日曜日

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


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


    依存関係プロパティ定義で「inherit」を指定しておくと、
     WPF「ロジカルな階層構造」の下へ、指定した値がが継承されて行く

    「inherit」の定義例
    > System.Windows.Controls.Button]::FontWeightProperty.DefaultMetadata.Inherits
      True   <--★これ

    サンプル画面 <--「Button2」にはFontWeightは指定がないが、
                                「StackPanel」でBoldにしてされている

imageコードはこのBlogの一番下

   「inherit」の追っかけ方(その1:下からさかのぼる

          ①ヘルパークラスで定義を見てみる
            > $b2 = $form.findname("btn2")
            > $dp2 = [System.Windows.Controls.Button]::FontWeightProperty
            > [System.Windows.DependencyPropertyHelper]::GetValueSource($b2, $dp2) | fl

                BaseValueSource : Inherited <--★継承されていることは分かった
                IsExpression    : False
                IsAnimated      : False
                IsCoerced       : False
                IsCurrent       : False

          ②指定されている値を見てみる
            > $b2 = $form.findname("btn2")
            > $dp2 = [System.Windows.Controls.Button]::FontWeightProperty
            > $b2.getvalue($dp2)
              Bold            <--★見えた

          ③LogicalTreeをさかのぼって、「FontWeight」プロパティをローカルで
               セットしている場所を探す

             ・1つ親にさかのぼる
            > $b2 = $form.findname("btn2")
            > $dp2 = [System.Windows.Controls.Button]::FontWeightProperty
            > $StackPanel = $b2.Parent

            > [System.Windows.DependencyPropertyHelper]::GetValueSource(`
                                                        $StackPanel, $dp2).BaseValueSource
              Inherited <--★ここも継承されている

            ・もう1つ親にさかのぼる
            > $GroupBox = $stackPanel.parent
            > [System.Windows.DependencyPropertyHelper]::GetValueSource(`
                                                              $GroupBox, $dp2).BaseValueSource
              Local   <-- ★(あった!!)

    「inherit」の追っかけ方(その2:上からたどる)
 
        ==> ロジカル階層(木構造)をすべてたどるツールを作って、
               それをベースに探索・表示した例 (ツール自身は自作なので省略)

        探索・表示の結果

         >System.Windows.Window                              name=""
            FontWeight :  Normal  ( Default )
           >System.Windows.Controls.GroupBox                 name="myGroupBox"
               FontWeight :  Bold  ( Local )                      <--★(これ!!)
              string                                                                     name=""
             >System.Windows.Controls.StackPanel             name=""
                  FontWeight :  Bold  ( Inherited )             <--★
               >System.Windows.Controls.Button               name="Button1"
                     FontWeight :  Medium  ( Local )
                  string                                                             name=""
               >System.Windows.Controls.Button               name="Button2"
                     FontWeight :  Bold  ( Inherited )           <—★
                  string                                                              name=""
               >System.Windows.Controls.Button               name="Button3"
                     FontWeight :  Normal  ( Local )
                  string                                         name=""


サンプルの実行例
PowershellだけでWPF表示(Powershell3.0でも2.0でも稼働)
.Netframeworkは3.0以上が必要
WPFの約束としてPowershellはSTAモードで動く必要あり
以下コードを

  ①Powershellコンソールにコピペして実行
  ②ISEで実行する時は、すでにSTAモードなので最初の6行は不要

    注意:ブラウザによってはコピペで行頭に余分な空白が出来てしまうことあり
           C:\temp> □'@ # ← ここの行の行頭に空白あると動かない


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

$xaml_win1 = @'
<Window
        xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="250" Width="280"
        >

    <Window.Resources>
        <LinearGradientBrush x:Key="gradBrush" StartPoint="0,0" EndPoint="1,1">
            <GradientStop Color="SteelBlue" Offset="0" />
            <GradientStop Color="PowderBlue" Offset="1"/>
        </LinearGradientBrush>
    </Window.Resources>

    <GroupBox FontWeight="Bold" Name="myGroupBox">
        <GroupBox.Header>
            Buttons
        </GroupBox.Header>
            <StackPanel Background="{StaticResource gradBrush}" Name="sp">
                <TextBlock FontFamily="Arial Black" Margin="7"
                           Background="{StaticResource gradBrush}">
                           Some Buttons</TextBlock>
                <Button Height="40" Name="btn1" FontWeight="Bold"
                           Background="{StaticResource gradBrush}">
                           Button 1</Button>
                <Button Height="40" Name="btn2"
                           Background="{StaticResource gradBrush}">
                           Button 2</Button>
            </StackPanel>
    </GroupBox>

</Window>
'@

if ($host.Version.Major -eq 3) {
    Add-Type -assembly WindowsBase,PresentationCore,PresentationFramework,System.Xaml,System.xml
} else {
    Add-Type -assembly WindowsBase,PresentationCore,PresentationFramework
}

$form = [System.Windows.Markup.XamlReader]::Parse($xaml_win1)
[void]$Form.ShowDialog()
#-------------------------------------------------

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アセンブリから一覧を得る
     面倒なので省略