2016-05-19 93 views
1

我想爲頭部特定的WPF數據網格(換句話說,每個列頭可能有它自己的上下文菜單不同於其他頭部)構造上下文菜單。 此外,支持上下文菜單的數據是綁定數據。 我的問題是,我似乎無法將我的菜單連接到我的數據上下文。 我從這裏或其他地方嘗試了一些建議,但到目前爲止沒有運氣。WPF中頭部特定的上下文菜單綁定

我知道上下文菜單不在文檔其餘部分的可視化樹中,所以我嘗試過使用它的PlacementTarget(如下所示),但是當我點擊列標題時,我的PlacementTarget只有標題的TextBlock。我如何從那裏到網格的DataContext?

這是什麼,我已經試過一個例子:

<Window x:Class="ContextMenuExample.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:local="clr-namespace:ContextMenuExample" 
    mc:Ignorable="d" 
    Title="MainWindow" Height="350" Width="525"> 
<Window.DataContext> 
    <local:ExampleViewModel /> 
</Window.DataContext> 
<Grid> 
    <DataGrid ItemsSource="{Binding MyGridData}" IsReadOnly="True" AutoGenerateColumns="False"> 
     <!-- THESE WORK, BUT THEY ARE GRID-GLOBAL. I WANT HEADER-SPECIFIC CONTEXT MENUS --> 
     <DataGrid.ContextMenu> 
      <ContextMenu> 
       <CheckBox Name="GridCheckbox1" Content="Grid Menu - Item1" IsChecked="{Binding Column1Checked, Mode=TwoWay}"/> 
       <CheckBox Name="GridCheckbox2" Content="Grid Menu - Item2" IsChecked="{Binding Column2Checked, Mode=TwoWay}"/> 
       <CheckBox Name="GridCheckbox3" Content="Grid Menu - Item3" IsChecked="{Binding Column3Checked, Mode=TwoWay}"/> 
      </ContextMenu> 
     </DataGrid.ContextMenu> 
     <DataGrid.Columns> 
      <DataGridTextColumn Header="Column 1 Data" Binding="{Binding Column1Data}" Width="Auto"> 
       <!-- ATTEMPT 1 - JUST SEE IF I CAN BIND DIRECTLY. SHOULDN'T WORK. --> 
       <!-- System.Windows.Data Error: 40 : BindingExpression path error: 'Column1Checked' property not found on 'object' ''String' (HashCode=-1586790989)'. BindingExpression:Path=Column1Checked; DataItem='String' (HashCode=-1586790989); target element is 'CheckBox' (Name='Header1Checkbox'); target property is 'IsChecked' (type 'Nullable`1') --> 
       <DataGridTextColumn.HeaderTemplate> 
        <DataTemplate> 
         <TextBlock Name="Header1TextBlock" Text="{TemplateBinding Content}" > 
          <TextBlock.ContextMenu> 
           <ContextMenu> 
            <CheckBox Name="Header1Checkbox" Content="Header Menu 1" IsChecked="{Binding Column1Checked, Mode=TwoWay}"/> 
           </ContextMenu> 
          </TextBlock.ContextMenu> 
         </TextBlock> 
        </DataTemplate> 
       </DataGridTextColumn.HeaderTemplate> 
      </DataGridTextColumn> 
      <DataGridTextColumn Header="Column 2 Data" Binding="{Binding Column1Data}" Width="Auto"> 
       <!-- ATTEMPT 2 - BIND TO THE PLACEMENT TARGET. THIS MAKES THE TextBlock MY DATA CONTEXT. CLOSER (?) BUT STILL WRONG --> 
       <!-- System.Windows.Data Error: 40 : BindingExpression path error: 'Column2Checked' property not found on 'object' ''TextBlock' (Name='Header2TextBlock')'. BindingExpression:Path=Column2Checked; DataItem='TextBlock' (Name='Header2TextBlock'); target element is 'CheckBox' (Name='Header2Checkbox'); target property is 'IsChecked' (type 'Nullable`1') --> 
       <DataGridTextColumn.HeaderTemplate> 
        <DataTemplate> 
         <TextBlock Name="Header2TextBlock" Text="{TemplateBinding Content}" > 
          <TextBlock.ContextMenu> 
           <ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}"> 
            <CheckBox Name="Header2Checkbox" Content="Header Menu 2" IsChecked="{Binding Column2Checked, Mode=TwoWay}"/> 
           </ContextMenu> 
          </TextBlock.ContextMenu> 
         </TextBlock> 
        </DataTemplate> 
       </DataGridTextColumn.HeaderTemplate> 
      </DataGridTextColumn> 
      <DataGridTextColumn Header="Column 3 Data" Binding="{Binding Column1Data}" Width="Auto"> 
       <!-- ATTEMPT 3 - BIND TO THE PLACEMENT TARGETS' CONTEXT. I'M NOT EVEN SURE WHAT THIS IS, BUT IT DOESN'T WORK --> 
       <!-- System.Windows.Data Error: 40 : BindingExpression path error: 'Column3Checked' property not found on 'object' ''String' (HashCode=975011251)'. BindingExpression:Path=Column3Checked; DataItem='String' (HashCode=975011251); target element is 'CheckBox' (Name='Header3Checkbox'); target property is 'IsChecked' (type 'Nullable`1') --> 
       <DataGridTextColumn.HeaderTemplate> 
        <DataTemplate> 
         <TextBlock Name="Header3TextBlock" Text="{TemplateBinding Content}" > 
          <TextBlock.ContextMenu> 
           <ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"> 
            <CheckBox Name="Header3Checkbox" Content="Header Menu 3" IsChecked="{Binding Column3Checked, Mode=TwoWay}"/> 
           </ContextMenu> 
          </TextBlock.ContextMenu> 
         </TextBlock> 
        </DataTemplate> 
       </DataGridTextColumn.HeaderTemplate> 
      </DataGridTextColumn> 
     </DataGrid.Columns> 
    </DataGrid> 
</Grid> 

class GridData 
{ 
    public int Column1Data { get; set; } 
    public int Column2Data { get; set; } 
    public int Column3Data { get; set; } 
} 

class ExampleViewModel : INotifyPropertyChanged 
{ 
    private bool column1Checked; 
    private bool column2Checked; 
    private bool column3Checked; 

    public event PropertyChangedEventHandler PropertyChanged; 

    public List<GridData> MyGridData 
    { 
     get 
     { 
      return new List<GridData> 
      { 
       new GridData() { Column1Data = 1, Column2Data = 2, Column3Data = 3}, 
       new GridData() { Column1Data = 4, Column2Data = 5, Column3Data = 6}, 
       new GridData() { Column1Data = 7, Column2Data = 8, Column3Data = 9} 
      }; 
     } 
    } 

    public bool Column1Checked 
    { 
     get { return column1Checked; } 
     set { 
      if (column1Checked != value) 
      { 
       column1Checked = value; 
       PropertyChanged(this, new PropertyChangedEventArgs(nameof(Column1Checked))); 
      } 
     } 
    } 
    public bool Column2Checked 
    { 
     get { return column2Checked; } 
     set { 
      if (column2Checked != value) 
      { 
       column2Checked = value; 
       PropertyChanged(this, new PropertyChangedEventArgs(nameof(Column2Checked))); 
      } 
     } 
    } 
    public bool Column3Checked 
    { 
     get { return column3Checked; } 
     set { 
      if (column3Checked != value) 
      { 
       column3Checked = value; 
       PropertyChanged(this, new PropertyChangedEventArgs(nameof(Column3Checked))); 
      } 
     } 
    } 
} 

所以我的問題是...我怎麼可以綁定我的上下文菜單我的ViewModel?

感謝您提供任何幫助。

回答

0

試試這個。

<DataGridTextColumn Header="Column 1 Data" Binding="{Binding Column1Data}" Width="Auto"> 
    <DataGridTextColumn.HeaderTemplate> 
     <DataTemplate> 
      <TextBlock Name="Header1TextBlock" Text="{TemplateBinding Content}"> 
       <TextBlock.ContextMenu> 
        <ContextMenu> 
         <CheckBox Name="Header1Checkbox" Content="Header Menu 1" IsChecked="{Binding DataContext.Column1Checked, RelativeSource={RelativeSource AncestorType=Window}, Mode=TwoWay}"/> 
        </ContextMenu> 
       </TextBlock.ContextMenu> 
      </TextBlock> 
     </DataTemplate> 
    </DataGridTextColumn.HeaderTemplate> 
</DataGridTextColumn> 

我也不太清楚,如果它的作品,因爲你的ContextMenu是一個模板中定義。

+0

喜Jai, 感謝您的幫助。 不幸的是,這不起作用。 我認爲,因爲'窗口'對象沒有DataContext這不管用。我試過'AncestorType = DataGrid',但那也行不通。這可能是因爲上下文菜單不是可視化樹的一部分,因此找到一個祖先是棘手的。 如果我能找到一種方法來產生相同的結果,而不用在DataTemplate中聲明我的ContextMenu,我會。我只是不知道如何得到我想要的任何其他方式的結果。 – kshill

0

我終於找到我需要的東西在這裏:
WPF ContextMenu woes: How do I set the DataContext of the ContextMenu?
由於daub815

這是對我工作:

   <DataGridTextColumn Header="Column 1 Data" Binding="{Binding Column1Data}" Width="Auto"> 
       <DataGridTextColumn.HeaderTemplate> 
        <DataTemplate> 
         <TextBlock Name="Header1TextBlock" Text="{TemplateBinding Content}" Tag="{Binding DataContext, ElementName=MyDataGrid}"> 
          <TextBlock.ContextMenu> 
           <ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}"> 
            <CheckBox Name="Header1Checkbox" Content="Header Menu 1" IsChecked="{Binding Column1Checked, Mode=TwoWay}"/> 
           </ContextMenu> 
          </TextBlock.ContextMenu> 
         </TextBlock> 
        </DataTemplate> 
       </DataGridTextColumn.HeaderTemplate> 
      </DataGridTextColumn> 

(其中MyDataGrid是DataGrid對象)