在datagrid中添加上下文菜单,如何获取select Item值

时间:2013-09-04 10:03:30

标签: c# wpf mvvm datagrid

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

 <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>

这是我的viewModel

 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]

非常感谢

5 个答案:

答案 0 :(得分:6)

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

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

现在我们可以访问DataContext的{​​{1}} UserControl,可以在每个数据对象的Tag属性中找到它,让我们从ContextMenu绑定到PlacementTarget ...我们使用名为<ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={ RelativeSource Self}}"> <MenuItem Header="Do Something" Command="{Binding YourCommandInYourViewModel}" CommandParameter="{Binding YourCollection.CurrentItem}"> ... </MenuItem> </ContextMenu> 的便利属性:

来实现
YourCollection.CurrentItem

需要注意的一件事是上面CommandParameter中显示的CurrentItem属性。 SelectedItem属性是我添加到我的集合类中的属性,用于绑定到UI中集合控件的SelectedItem属性。如果你没有其中一个,那没关系,但你需要一个绑定到你的集合控件的<ListBox ItemsSource="{Binding YourCollection}" SelectedItem="{Binding YourCollection.CurrentItem}" /> 属性的属性才能工作。就我的例子而言,我有这个:

{{1}}

答案 1 :(得分:5)

展开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 :(得分:1)

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

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

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

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

我认为这是类似的情况。我以这种方式解决了这个问题:

<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>.