문제

ElementName을 사용한 바인딩이 올바르게 해결되지 않는다는 사실을 알아차린 사람이 있습니까? MenuItem 안에 포함된 객체 ContextMenu 사물?이 샘플을 확인하세요.

<Window x:Class="EmptyWPF.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300"
    x:Name="window">
    <Grid x:Name="grid" Background="Wheat">
        <Grid.ContextMenu>
            <ContextMenu x:Name="menu">
                <MenuItem x:Name="menuItem" Header="Window" Tag="{Binding ElementName=window}" Click="MenuItem_Click"/>
                <MenuItem Header="Grid" Tag="{Binding ElementName=grid}" Click="MenuItem_Click"/>
                <MenuItem Header="Menu" Tag="{Binding ElementName=menu}" Click="MenuItem_Click"/>
                <MenuItem Header="Menu Item" Tag="{Binding ElementName=menuItem}" Click="MenuItem_Click"/>
            </ContextMenu>
        </Grid.ContextMenu>
        <Button Content="Menu" 
                HorizontalAlignment="Center" VerticalAlignment="Center" 
                Click="MenuItem_Click" Tag="{Binding ElementName=menu}"/>
        <Menu HorizontalAlignment="Center" VerticalAlignment="Bottom">
            <MenuItem x:Name="anotherMenuItem" Header="Window" Tag="{Binding ElementName=window}" Click="MenuItem_Click"/>
            <MenuItem Header="Grid" Tag="{Binding ElementName=grid}" Click="MenuItem_Click"/>
            <MenuItem Header="Menu" Tag="{Binding ElementName=menu}" Click="MenuItem_Click"/>
            <MenuItem Header="Menu Item" Tag="{Binding ElementName=anotherMenuItem}" Click="MenuItem_Click"/>
        </Menu>
    </Grid>
</Window>

ContextMenu에 포함된 바인딩을 제외한 모든 바인딩은 훌륭하게 작동합니다.런타임 중에 출력 창에 오류를 인쇄합니다.

해결 방법을 아는 사람이 있습니까?여기서 무슨 일이 일어나고 있는 걸까요?

도움이 되었습니까?

해결책

훨씬 간단한 솔루션을 찾았습니다.

Usercontrol의 뒤에있는 코드에서 :

NameScope.SetNameScope(contextMenu, NameScope.GetNameScope(this));

다른 팁

다른 사람들이 말했듯이, 'ContextMenu'는 시각적 트리에 포함되어 있지 않으며 'ElementName'바인딩은 작동하지 않습니다. 허용 된 답변에서 제안한대로 문맥 메뉴의 'Namescope'를 설정하면 컨텍스트 메뉴가 'DataTemplate'에 정의되지 않은 경우에만 작동합니다. 나는 이것을 사용하여 이것을 해결했다 {x : reference} Markup-extension 이는 'Emplicname'바인딩과 유사하지만 시각적 트리를 우회하여 바인딩을 다르게 해결합니다. 나는 이것이 'PlacementTarget'을 사용하는 것보다 훨씬 더 읽기 쉬운 것으로 생각합니다. 예는 다음과 같습니다.

<Image Source="{Binding Image}">       
    <Image.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Delete" 
                      Command="{Binding Source={x:Reference Name=Root}, Path=DataContext.RemoveImage}"
                      CommandParameter="{Binding}" />
        </ContextMenu>
    </Image.ContextMenu>
</Image>

MSDN-Documentation에 따르면

X : 참조는 XAML 2009에 정의 된 구성입니다. WPF에서는 XAML 2009 기능을 사용할 수 있지만 WPF 마크 업 컴파일이 아닌 XAML에만 사용할 수 있습니다. Markup 컴파일 된 XAML과 BAML 형태의 XAML은 현재 XAML 2009 언어 키워드 및 기능을 지원하지 않습니다.

그 의미가 무엇이든 ...하지만 저에게 효과가 있습니다.

다음은 또 다른 XAML 전용 해결 방법입니다. (이것은 또한 당신이 내부의 것을 원한다고 가정합니다. DataContext, 예를 들어, 당신은입니다 mvvming 그것)

옵션 1, 여기서 부모의 요소 문맥 메뉴 a DataTemplate:

Command="{Binding PlacementTarget.DataContext.MyCommand, 
         RelativeSource={RelativeSource AncestorType=ContextMenu}}"

이것은 OP의 질문에 효과가 있습니다. 당신이 a 안에 있으면 작동하지 않습니다 DataTemplate. 이 경우 DataContext 종종 컬렉션의 많은 사람들 중 하나이며 나는 명령한다 당신은 동일한 뷰 모델 내에서 컬렉션의 형제 자매입니다 ( DataContext 창문의 말).

이 경우, 당신은 꼬리표 부모를 일시적으로 유지합니다 DataContext 여기에는 컬렉션과 iCommand가 모두 포함되어 있습니다.

class ViewModel
{
    public ObservableCollection<Derp> Derps { get;set;}
    public ICommand DeleteDerp {get; set;}
} 

그리고 XAML에서

<!-- ItemsSource binds to Derps in the DataContext -->
<StackPanel
    Tag="{Binding DataContext, ElementName=root}">
    <StackPanel.ContextMenu>
        <ContextMenu>
            <MenuItem
                Header="Derp"                       
                Command="{Binding PlacementTarget.Tag.DeleteDerp, 
                RelativeSource={RelativeSource 
                                    AncestorType=ContextMenu}}"
                CommandParameter="{Binding PlacementTarget.DataContext, 
                RelativeSource={RelativeSource AncestorType=ContextMenu}}">
            </MenuItem>

컨텍스트 메뉴는 묶기가 까다로워집니다. 그것들은 당신의 통제의 시각적 트리 외부에 존재하므로 요소 이름을 찾을 수 없습니다.

컨텍스트 메뉴의 데이터 콘텍스트를 배치 대상으로 설정하십시오. 친척 소스를 사용해야합니다.

<ContextMenu 
   DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}"> ...

조금 실험 한 후, 나는 하나의 작품을 발견했습니다.

최상위 레벨을 만드십시오 Window/UserControl 구현하다 INameScope 그리고 설정 NameScopeContextMenu 최상위 제어로.

public class Window1 : Window, INameScope
{
    public Window1()
    {
        InitializeComponent();
        NameScope.SetNameScope(contextMenu, this);
    }

    // Event handlers and etc...

    // Implement INameScope similar to this:
    #region INameScope Members

    Dictionary<string, object> items = new Dictionary<string, object>();

    object INameScope.FindName(string name)
    {
        return items[name];
    }

    void INameScope.RegisterName(string name, object scopedElement)
    {
        items.Add(name, scopedElement);
    }

    void INameScope.UnregisterName(string name)
    {
        items.Remove(name);
    }

    #endregion
}

이것은 컨텍스트 메뉴가 Window. 다른 옵션이 있습니까?

이미 처리하고 있는 마우스 클릭에 대한 이벤트 핸들러 내부의 한 줄의 코드를 피하기 위해 마술 트릭에 의존하는 이유가 무엇인지 잘 모르겠습니다.

    private void MenuItem_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        // this would be your tag - whatever control can be put as string intot he tag
        UIElement elm = Window.GetWindow(sender as MenuItem).FindName("whatever control") as UIElement;
    }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top