3

menuItem の親を取得する方法がわかりません。色々と調べてみたのですが、なかなか良い回答が得られません...

私のXAMLは次のとおりです。

<DockPanel>
            <Menu DockPanel.Dock="Right" SnapsToDevicePixels="True" Margin="2,0,0,0">
                <MenuItem Header="Devices">
                    <local:MenuItemWithRadioButton x:Name="MenuItemVideoDevices" Header="Video">
                    </local:MenuItemWithRadioButton>
                    <local:MenuItemWithRadioButton x:Name="MenuItemAudioDevices" Header="Audio">
                    </local:MenuItemWithRadioButton>
                </MenuItem>
            </Menu>
</DockPanel>

private void MenuItemWithRadioButtons_Click(object sender, System.Windows.RoutedEventArgs e)
{
        MenuItem mi = sender as MenuItem;
        if (mi != null)
        {
            RadioButton rb = mi.Icon as RadioButton;
            if (rb != null)
            {
                rb.IsChecked = true;
            }
            //Here I want to get the parent menuItem
        }            
}

コードでは、"MenuItemVideoDevices" のような submenuItem をクリックすると、イベント処理関数がトリガーされますが、この関数で menuItem "Video" を取得する方法がわかりません。

誰でも知っていますか?

4

2 に答える 2

2

MenuItem.Parentプロパティがであることがわかった場合null、コードは投稿したほど単純ではありません。次の単純な XAML ウィンドウをまとめたところ、問題なく動作しました。

<Window x:Class="TestSO16231375MenuItemParent.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
  <DockPanel>
    <Menu DockPanel.Dock="Right" SnapsToDevicePixels="True" Margin="2,0,0,0">
      <MenuItem Header="Devices">
        <MenuItem x:Name="MenuItemVideoDevices" Header="Video" Click="MenuItemVideoAudioDevices_Click"/>
        <MenuItem x:Name="MenuItemAudioDevices" Header="Audio" Click="MenuItemVideoAudioDevices_Click"/>
      </MenuItem>
    </Menu>
  </DockPanel>
</Window>

つまり、Clickイベント ハンドラーは、次のプロパティMenuItemを使用して、予期される正しい親を正常に取得できます。Parent

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void MenuItemVideoAudioDevices_Click(object sender, RoutedEventArgs e)
    {
        MenuItem menuItem = (MenuItem)sender;

        MessageBox.Show("Parent's header text: " + ((MenuItem)menuItem.Parent).Header.ToString());
    }
}


問題を確実に再現する優れた最小限の完全なコード例を 提供しなかったため、Parentプロパティがnullテストに含まれていた理由を確実に言うことはできません。ただし、私自身のシナリオ (この質問に私を導いたもの) では、問題は私の子テンプレートであるため、プロパティMenuItemに null 以外の値が含まれていないことです。プロパティのドキュメントで次のParentコメントに注意してください。FrameworkElement.Parent

テンプレートの場合、テンプレートの Parent は最終的に null になります。この時点を過ぎて、テンプレートが実際に適用される論理ツリーに拡張するには、TemplatedParent を使用します。

このアドバイスに従うのは簡単ではないことがわかりました。私のParent財産はnull最初からありました。ただし、MenuItemオブジェクトのTemplatedParentプロパティ論理的な親 ( によって取得されるLogicalTreeHelper.GetParent()) も同様でした。

私がしなければならなかったことは、ビジュアル ツリーをたどって、論理的な親を持つ最初の親ノードを見つけることでした。その時点で、そのノードのプロパティを使用して実際の親TemplatedParentを取得できました。MenuItem

これを一般化するための簡単なヘルパー メソッドを作成しました。これまでのところ、私がそれを使用している唯一のシナリオはこのMenuItemシナリオであり、これが他の場合に必要になるかどうかは本当にわかりません. しかし、それは私にとってはうまくいき、他の子オブジェクトで同様の問題に遭遇した場合 (または他の誰かがそうする場合) に備えて、良い出発点のように思えます。

拡張メソッドとして記述すると、次のようになります。

public static T GetTemplatedParent<T>(this FrameworkElement o)
    where T : DependencyObject
{
    DependencyObject child = o, parent = null;

    while (child != null && (parent = LogicalTreeHelper.GetParent(child)) == null)
    {
        child = VisualTreeHelper.GetParent(child);
    }

    FrameworkElement frameworkParent = parent as FrameworkElement;

    return frameworkParent != null ? frameworkParent.TemplatedParent as T : null;
}

MenuItemこれにより、他のオブジェクトを導入することなく、テンプレート化されたオブジェクトの親オブジェクトを取得できMenuItemます (明らかに、静的フィールドをどこかで初期化し、その値を取得するだけで問題を解決できたはずですが、それは非常にハックです...もっと一般的なものが欲しかった-目的と信頼性)。

于 2015-06-18T23:19:49.233 に答える