【问题标题】:Add context menu in datagrid, how to get the select Item value在datagrid中添加上下文菜单,如何获取选择项值
【发布时间】:2013-09-04 10:03:30
【问题描述】:

我是使用 MVVM 模式进行 WPF 编程的新手。现在我在数据网格中添加了上下文菜单。但是,当我单击鼠标右键时,我不知道如何获取选择行值。 这是我的圣诞节

 <DataGrid  AutoGenerateColumns="False" Grid.Row="1" CanUserAddRows="False" CanUserDeleteRows="False"
              ItemsSource="{Binding StoryList}">
        <DataGrid.Columns>
        <DataGridTextColumn Header="ID" Binding="{Binding ID}" Width="40" IsReadOnly="True" />
        <DataGridTextColumn Header="Title" Binding="{Binding Title}" Width="60" IsReadOnly="True"/>
        <DataGridTextColumn Header="StoryPoints" Binding="{Binding StoryPoints}" Width="90" IsReadOnly="True">
                <DataGridTextColumn.CellStyle>
                    <Style TargetType="DataGridCell">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding StoryPoints}" Value="0">
                                <Setter Property="Background" Value="Red"/>
                                <Setter Property="ToolTip" Value="Story Point cannot be 0."/>
                            </DataTrigger>                                
                        </Style.Triggers>
                    </Style>
                </DataGridTextColumn.CellStyle>
            </DataGridTextColumn>
            <DataGridTextColumn Header="Stack Rank" Binding="{Binding StackRank}" Width="80"/>
            <DataGridTextColumn Header="Estimate" Binding="{Binding Estimate}" Width="60"/>
            <DataGridTextColumn Header="CompletedWork" Binding="{Binding CompletedWork}" Width="120" />
            <DataGridTextColumn Header="RemainWork" Binding="{Binding RemainWork}" Width="110" />
            <DataGridTextColumn Header="CompleteProcess" Binding="{Binding CompletedProcess}" Width="110" />
            <DataGridTextColumn Header="YesterdayComments" Binding="{Binding YesterdayComments}" Width="120" />
            <DataGridTextColumn Header="TodayComments" Binding="{Binding TodayComments}" Width="120" />
        </DataGrid.Columns>
        <DataGrid.ContextMenu>
            <ContextMenu Name="StoryMenu" StaysOpen="True">
                <MenuItem Header="Add an Issue" Command="{Binding AddIssueCommand}" />
                <MenuItem Header="Burn Down Chart" Command="{Binding BurnDownChartCommand}"/>
            </ContextMenu>
        </DataGrid.ContextMenu>
    </DataGrid>

这是我的视图模型

 class MainViewModel:NotificationObject
{
    private ObservableCollection<Story> storyList;

    public ObservableCollection<Story> StoryList
    {
        get { return storyList; }
        set
        {
            storyList = value;
            this.RaisePropertyChanged("StoryList");
        }
    }
    public DelegateCommand AddIssueCommand { get; set; }
    public DelegateCommand BurnDownChartCommand { get; set; }
    private Story selectStory;

    public Story SelectStory
    {
        get { return selectStory; }
        set
        {
            selectStory = value;
            this.RaisePropertyChanged("SelectStory");
        }
    }

    public void LoadStory()
    {
        this.storyList = new ObservableCollection<Story>();
        Story story1 = new Story(){ID=1, Title="win App", StoryPoints=0, StackRank=1, Estimate=40, CompletedWork=10, RemainWork=30, CompletedProcess=25, TodayComments="Coding", YesterdayComments="N/a"};
        Story story2 = new Story() { ID = 2, Title = "win App", StoryPoints = 10, Estimate = 40, CompletedWork = 10, RemainWork = 30, CompletedProcess = 25, TodayComments = "Coding 20%", YesterdayComments = "N/a" };
        Story story3 = new Story() { ID = 3, Title = "win App", StoryPoints = 10, Estimate = 50, CompletedWork = 20, RemainWork = 30, CompletedProcess = 20, TodayComments = "Coding  30%", YesterdayComments = "N/a" };
        Story story4 = new Story() { ID = 4, Title = "win App", StoryPoints = 10, Estimate = 60, CompletedWork = 30, RemainWork = 30, CompletedProcess = 50, TodayComments = "Coding  40%", YesterdayComments = "N/a" };
        Story story5 = new Story() { ID = 5, Title = "win App", StoryPoints = 10, Estimate = 40, CompletedWork = 10, RemainWork = 30, CompletedProcess = 25, TodayComments = "Coding  50%", YesterdayComments = "N/a" };
        Story story6 = new Story() { ID = 6, Title = "win App", StoryPoints = 10, Estimate = 30, CompletedWork = 30, RemainWork = 0, CompletedProcess = 100, TodayComments = "Coding  60%", YesterdayComments = "N/a" };

        storyList.Add(story1);
        storyList.Add(story3);
        storyList.Add(story2);
        storyList.Add(story4);
        storyList.Add(story5);
        storyList.Add(story6);
    }
    public MainViewModel()
    {
        this.SelectStory = new Story();
        this.LoadStory();
        this.AddIssueCommand = new DelegateCommand(new Action(this.AddIssueCommandExecute));
    }

    public void AddIssueCommandExecute()
    {

        if (SelectStory != null)
        {
            System.Windows.MessageBox.Show("Add an Issue" + SelectStory.Title + "!");
        }
        else
        {
            System.Windows.MessageBox.Show("choose an story first!");
        }
        //System.Windows.MessageBox.Show("record" + RecordIndex);
    }
}![What I need][1]

非常感谢

【问题讨论】:

  • 为什么上下文菜单需要选中项的值? addissuecommand 和 burndowncommand 对选定的项目起作用吗?
  • SelectedItem绑定到viewmodel中的一个属性并使用它。
  • 是的,addIssueCommand 和 burndownCommand 可以处理它。谢谢@nit

标签: c# wpf mvvm datagrid


【解决方案1】:

Bolu's comment 上展开,您可以使用SelectedItem 来获取当前项目。下面是一个简单的例子:

<DataGrid ItemsSource="{Binding Source}" SelectedItem="{Binding SelectedItemProperty, Mode=TwoWay}">
    <DataGrid.ContextMenu>
        <ContextMenu>
            <MenuItem Command="{Binding MyCommand}" Header="MyCommand"/>
        </ContextMenu>
    </DataGrid.ContextMenu>
    <DataGrid.Columns>
        <DataGridTextColumn Header="Name" Binding="{Binding Key, Mode=TwoWay}" Width="1*"/>
        <DataGridTextColumn Header="Value" Binding="{Binding Value, Mode=TwoWay}" Width="3*"/>
    </DataGrid.Columns>
</DataGrid>

SelectedItem 现在绑定到 ViewModel 中的 SelectedItemProperty

【讨论】:

  • 这似乎是最干净的解决方案,对我有用。不知道为什么它没有赞成票。
【解决方案2】:

这是 WPF 中的常见问题。解决方案是利用DataTemplate 项中的Tag 属性来保存数据项。首先,让我们添加这部分:

<DataTemplate DataType="{x:Type YourDataTypeXmlNamespace:YourDataType}">
    <Border Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType={
x:Type YourViewsXmlNamespace:YourViewWhereThisIsDeclared}}}">
        ...
    </Border>
</DataTemplate>

现在我们可以访问UserControlDataContext,可以在每个数据对象的Tag 属性中找到,让我们从ContextMenu 绑定到它...我们使用名为PlacementTarget 的方便属性:

<ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={
RelativeSource Self}}">
    <MenuItem Header="Do Something" Command="{Binding YourCommandInYourViewModel}" 
CommandParameter="{Binding YourCollection.CurrentItem}">
        ...
    </MenuItem>
</ContextMenu>

需要注意的是上面CommandParameter 中显示的YourCollection.CurrentItem 属性。 CurrentItem 属性是我添加到集合类中的一个属性,用于绑定到 UI 中集合控件的 SelectedItem 属性。如果您没有其中之一,没关系,但是您需要一个绑定到集合控件的SelectedItem 属性的属性才能使其工作。对于我的例子,我有这个:

<ListBox ItemsSource="{Binding YourCollection}" SelectedItem="{Binding 
YourCollection.CurrentItem}" />

【讨论】:

  • 非常感谢您的帮助,@Sheridan。我已经解决了这个问题。准确地说,我用另一种方法来解决它。我创建了一个 MouseRightButton 类
  • 我将依赖属性添加到 UIElement 右键。然后我添加了 "
  • 因为这个注释不允许粘贴编码。以后可能会写个博客把链接贴在这里
  • @Echo,问题作者通常会在他们的 question 末尾添加一个明确标记为“更新”或“编辑”或“解决方案”的部分,并包括对他们找到的解决方案的描述。
  • @Sheridan 我更喜欢这种模式,如果有人回答他们自己的问题,他们只需将其作为单独的答案发布,并将其标记为已接受的答案。谁在这个网站上并不重要,重要的是什么!
【解决方案3】:

bigworld12 在这里的答案接近正确,但如果您的上下文菜单是模板化的,它就会中断。试试:

DataGridRow row =
            ((sender as MenuItem)?.GetAncestors()
               ?.FirstOrDefault(dpo => dpo.GetType() == typeof(ContextMenu)) as ContextMenu)
               ?.PlacementTarget as DataGridRow;

用于代码隐藏。我使用了可为空的运算符,以防您以某种方式到达这里而没有预期的父树和目标(可能通过在离开网格时触发上下文菜单。)

【讨论】:

    【解决方案4】:

    我知道这是一个老问题,但我想分享这个非常简单的解决方案。

    XAML:

    <ContextMenu x:Key="MyRowMenu1" DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">
         <MenuItem Click="MenuItem_Click" Header="Add to Favourites"/>
         <MenuItem Header="Copy" >
         <MenuItem Header="Copy Name"/>
         <MenuItem Header="Copy ID" />
         <MenuItem Header="Copy IP Adddress"/>
        </MenuItem>
    </ContextMenu>
    

    后面的代码:

    Private Sub MenuItem_Click(sender As Object, e As RoutedEventArgs)
        Dim row As DataGridRow = DirectCast(DirectCast(DirectCast(sender, MenuItem).GetParentObject, ContextMenu).PlacementTarget, DataGridRow)
        'replace with what ever item you want
        Dim srvr As Server = DirectCast(row.Item, Server)
    
    End Sub
    

    【讨论】:

      【解决方案5】:

      我认为这是一个类似的案例。我是这样解决的:

      <ContextMenu x:Key="rowContextMenu" Background="Transparent" >
      <MenuItem Header="{StaticResource LowPriority}" Style="{StaticResource menuStyle}"  
      CommandParameter="1" Click="ChangePriority"/>
      </ContextMenu>
      

      C#代码:

          private async void ChangePriority(object sender, RoutedEventArgs a)
          {
              MyTypeInRow row = (MyTypeInRow)(((MenuItem)sender).DataContext);
           ...
          }
      
         DataGrid.ItemsSource contains ObservableCollection<MyTypeInRow>. 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-02
        • 2021-08-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多