2

データグリッドのボタンに関連付けられたコンテキストメニューがあります。ビューモデルにある文字列のリストに基づいてコンテキストメニュー項目を変更したい。ボタンをクリックしても何も表示されません。

これが私が使用しているxamlで、データグリッドにあります。

<Button Grid.Column="1" Content="..."  Click="Button_Click">
        <Button.ContextMenu>
       <ContextMenu ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},Path=DataContext.SelectableDescriptions}">    
         <TextBlock Text="{Binding}"/>
       </ContextMenu>
       </Button.ContextMenu>        
</Button>

DataGridxaml全体は次のとおりです。

<DataGrid Grid.Row="1" Grid.ColumnSpan="4" CanUserAddRows="True" AutoGenerateColumns="False" CanUserDeleteRows="True"  ItemsSource="{Binding JobPricings, Mode=TwoWay}" SelectedItem="{Binding SelectedJobPricing, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
    <DataGrid.Columns>
        <DataGridTemplateColumn  Header="Description" Width="25*"   >
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="75*"/>
                            <ColumnDefinition Width="25*"/>
                        </Grid.ColumnDefinitions>
                        <TextBox Grid.Column="0" Text="{Binding Description,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                        <Button Grid.Column="1" Content="..."  Click="Button_Click">
                            <Button.ContextMenu>
                                <ContextMenu ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},Path=DataContext.SelectableDescriptions}">
                                    <TextBlock Text="{Binding}"/>
                                </ContextMenu>
                            </Button.ContextMenu>
                        </Button>
                    </Grid>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
         </DataGridTemplateColumn>
        <DataGridTextColumn Header="Unit Price" Binding="{Binding UnitPrice, Mode=TwoWay}" Width="25*"/>
        <DataGridTextColumn Header="Unit" Binding="{Binding Unit, Mode=TwoWay}" Width="25*"/>
        <DataGridTemplateColumn  Header="Currency   " Width="25*" >
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Grid>
                        <ComboBox  SelectedValue="{Binding CurrencyID, Mode=TwoWay}" SelectedValuePath="ID" DisplayMemberPath="Description" ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},Path=DataContext.Currencies}"  ></ComboBox>
                    </Grid>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

ビューモデルを介してコンテキストメニューをバインドしているプロパティは次のとおりです。

public ObservableCollection<string> SelectableDescriptions
{
    get
    {
        _selectableDescriptions.Add("One");
        _selectableDescriptions.Add("Two");
        return _selectableDescriptions;
    }
    set
    {
        _selectableDescriptions = value;
    }
}

リストがコンテキストメニューに表示されない理由について何か考えはありますか?

4

4 に答える 4

7

Johnが言うように、これContextMenuはボタンのビジュアルツリーから分離された独自の独立したウィンドウであるため、ボタンのを自動的に継承することはありませんDataContext

ただし、ContextMenuには、配置されているオブジェクト(この場合はボタン)へのリンクが1つありますPlacementTarget。メニューのPlacementTargetに移動すると、ボタンが見つかります。ボタンが見つかったら、そのDataContextを見つけることができます。

したがって、xamlでは、独自のDataContextを独自のにバインドPlacementTarget.DataContextすることでContextMenuにボタンのDataContextを手動で継承させることができ、他のすべてのバインド(たとえばItemsSource)は通常のように記述できます。

<Button Grid.Column="1" Content="..."  Click="Button_Click">
    <Button.ContextMenu>
        <ContextMenu DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.DataContext}" 
                     ItemsSource="{Binding Path=SelectableDescriptions}" >    
            <ContextMenu.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Path=SomePropertyOnItem}" />
                </DataTemplate>
            </ContextMenu.ItemTemplate>                            
        </ContextMenu>
    </Button.ContextMenu>        
</Button>
于 2013-01-29T21:30:19.913 に答える
3

ContextMenuやPopupなどはメインのビジュアルツリーの外部に存在するため、RelativeSourceを使用して親オブジェクトに移動することはできません。ほとんどの場合、ElementNameも壊れます。特定の状況に応じて、さまざまな回避策を利用できます。継承された添付プロパティを使用して追加のデータを渡すのが好きです。VMを変更する必要がなく、セットアップ後もXAMLにそのまま残ります。例を使用してテクニックを説明するブログ投稿は次のとおりです。http://blogs.interknowlogy.com/2011/04/26/binding-to-alternate-datacontexts/

于 2013-01-29T16:33:23.487 に答える
0

私はあなたがあなたのコンテキストメニューにこのようなことをしなければならないと思います、私の仮定はあなたが通貨を設定する方法が機能しているということであることに注意してください。

<ContextMenu>
    <ContextMenu.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}"/>
        </DataTemplate>
    </ContextMenu.ItemTemplate>
</ContextMenu>
于 2013-01-29T16:30:13.613 に答える
0

結局、コードビハインドでContextMenuのItemsSourceを設定しました(実際にはそのアプローチを使用したくありませんでしたが:)、これは機能しました

これがxamlです

<Button Grid.Column="1" Content="..."  Name="ellipseButton" Click="ellipseButton_Click">
    <Button.ContextMenu>
       <ContextMenu >
          <ContextMenu.ItemTemplate>
              <DataTemplate>
                   <TextBlock Text="{Binding}" />
              </DataTemplate>
          </ContextMenu.ItemTemplate>
        </ContextMenu>
     </Button.ContextMenu>
</Button>

背後にあるコードは次のとおりです。

private void ellipseButton_Click(object sender, RoutedEventArgs e)
{
    var button = sender as Button;
    button.ContextMenu.ItemsSource = JobPricingViewModel.SelectableDescriptions;
    if (button != null) button.ContextMenu.IsEnabled = true;
    var placementTarget = sender as Button;
    if (placementTarget != null) placementTarget.ContextMenu.PlacementTarget = placementTarget;
    var button1 = sender as Button;
    if (button1 != null)
        button1.ContextMenu.Placement = System.Windows.Controls.Primitives.PlacementMode.Bottom;
    var button2 = sender as Button;
    if (button2 != null) button2.ContextMenu.IsOpen = true;
}
于 2013-02-06T21:38:33.460 に答える