【问题标题】:Command Parameter Datagrid SelectedItems is null命令参数 Datagrid SelectedItems 为空
【发布时间】:2015-05-16 06:42:14
【问题描述】:

所以我找到了这个答案Pass command parameter from the xaml,我认为它让我大部分时间都在那里。我遇到的问题是,当我在数据网格中选择一行时,它会触发命令,但所选项目为空。

我不知道并且怀疑是问题所在,我应该在视图模型中将选定项传递给什么类型?目前我正在使用 IList,如我的视图模型代码所示:

namespace Project_Manager.ViewModel
{
public class ProjectSummaryViewModel : ObservableObject
{
    public ProjectSummaryViewModel()
    {
        ProjectSummary = DatabaseFunctions.getProjectSummaryData();
    }

    private ObservableCollection<ProjectSummaryModel> projectsummary;
    public ObservableCollection<ProjectSummaryModel> ProjectSummary
    {
        get { return projectsummary; }
        set
        {
            projectsummary = value;
            OnPropertyChanged("ProjectSummary");
        }
    }

    public ICommand DeleteRowCommand
    {
        get { return new ParamDelegateCommand<IList<ProjectSummaryModel>>(DeleteRow); }
    }

    private void DeleteRow(IList<ProjectSummaryModel> projectsummaryselected)
    {
        string name = projectsummaryselected[0].ProjectName;
    }
}
}

数据网格的 XAML 视图代码如下所示:

<Window x:Class="Project_Manager.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">

<!--<Window.Resources>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>-->

    <Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/> <!--Menu row-->
        <RowDefinition Height="Auto"/> <!--button row-->
        <RowDefinition/> <!--Current projects-->
        <RowDefinition/> <!--Completed projects-->
    </Grid.RowDefinitions>

    <!--<Menu>
        <MenuItem Header="File">
            <MenuItem Header="New Project Management" CommandTarget="{Binding NewTable}"/>
            <MenuItem Header="Open Project Management"/>
            <Separator/>
            <MenuItem Header="Exit"/>
        </MenuItem>
        <MenuItem Header="View">
            <MenuItem x:Name="ViewCompleted" IsCheckable="True" IsChecked="True" Header="View Completed Projects List"/>
        </MenuItem>
        <MenuItem Header="Project Management">
            <MenuItem Header="New Project"/>
        </MenuItem>

    </Menu>-->

    <StackPanel Grid.Row="1" Orientation="Horizontal">
        <Button Content="Create New Project" Command="{Binding Path=NewProjectCommand}"/>
        <!--<Button Content="View Details" Visibility="{Binding Source={x:Reference Name=CurrentProjectsDataGrid}, Path=IsSelected, Converter={StaticResource BooleanToVisibilityConverter}}"/>-->
    </StackPanel>

    <Grid Grid.Row="2">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBlock Text="Current Projects" Background="LemonChiffon"/>
        <DataGrid x:Name="SummaryDataGrid" ItemsSource="{Binding ProjectSummary}" Grid.Row="1" AutoGenerateColumns="True" Style="{StaticResource DataGridStyle}">
            <DataGrid.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Delete Row" Command="{Binding DeleteRowCommand}" CommandParameter="{Binding SelectedItems, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"/>
                </ContextMenu>
            </DataGrid.ContextMenu>
        </DataGrid>
    </Grid>


    <!--<DataGrid.Columns>
                <DataGridTextColumn Header="Project Name" Binding=""/>
                <DataGridTextColumn Header="Team Name"/>
                <DataGridTextColumn Header="Latest Update"/>
                <DataGridTextColumn Header="Date Started"/>
            </DataGrid.Columns>-->

    <!--<Grid Grid.Row="3">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        --><!--<TextBlock Text="Completed Projects" Background="LightGreen" Visibility="{Binding Source={x:Reference Name=ViewCompleted}, Path=IsChecked, Converter={StaticResource BooleanToVisibilityConverter}}"/>
        <DataGrid Grid.Row="1" AutoGenerateColumns="False" Style="{StaticResource DataGridStyle}" Visibility="{Binding Source={x:Reference Name=ViewCompleted}, Path=IsChecked, Converter={StaticResource BooleanToVisibilityConverter}}">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Project Name"/>
                <DataGridTextColumn Header="Team"/>
                <DataGridTextColumn Header="Date Completed"/>
            </DataGrid.Columns>
        </DataGrid>--><!--
    </Grid>-->
</Grid>

如果这是一个命令实现问题,这里是我正在使用的自定义委托命令:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;

namespace Project_Manager.Common
{
public class ParamDelegateCommand<T> : ICommand
{
    public event EventHandler CanExecuteChanged;

    private Action<T> executeMethod;

    //private Func<T, bool> canExecuteMethod;

    public ParamDelegateCommand(Action<T> executeMethod) //, Func<T, bool> canExecuteMethod)
    {
        this.executeMethod = executeMethod;
        //this.canExecuteMethod = canExecuteMethod;
    }

    public bool CanExecute(object parameter)
    {
        return true; //canExecuteMethod((T)parameter);
    }

    public void Execute(object parameter)
    {
        executeMethod((T)parameter);
    }
}
}

我已经四处搜索,可以找到很多 XAML 绑定的示例,但我似乎找不到它的另一半。那么视图模型中应该是什么类型呢?或者,实际问题是什么?

编辑:刚刚注意到调试窗口的错误可能对某人有所帮助

System.Windows.Data 错误:4:找不到与引用'RelativeSource FindAncestor,AncestorType='System.Windows.Controls.DataGrid',AncestorLevel='1''的绑定源。 BindingExpression:Path=SelectedItems;数据项=空;目标元素是'MenuItem'(名称='');目标属性是'CommandParameter'(类型'Object')

【问题讨论】:

    标签: wpf mvvm binding datagrid commandparameter


    【解决方案1】:

    如果您使用上下文菜单,请参考以下代码以获取 SelectedItems。

    <ContextMenu>
        <MenuItem Header="Delete Row" Command="{Binding DeleteRowCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}, Path=PlacementTarget.SelectedItems}"/>
    </ContextMenu>
    

    Selecteditems 也是一个 IList,因此请更改如下代码。

    public ICommand DeleteRowCommand
    {
        get { return new ParamDelegateCommand<IList>(DeleteRow); }
    }
    
    private void DeleteRow(IList projectsummaryselected)
    {
        string name = (projectsummaryselected[0] as ProjectSummaryModel).ProjectName;
    }
    

    【讨论】:

    • 大部分都有效!我现在得到了选定的项目,但如果我使用 'string name = projectssummaryselected[0].ProjectName;'我收到一个错误对象不包含 ProjectName 的定义并且找不到扩展方法。这很奇怪,因为如果我查看 'projectsummaryselected[0].ToString();'然后我看到 ProjectName 有一个值。我该如何到达?
    • 编辑我的答案。您需要进行类型转换才能获得列表。
    • 万一其他人发现这一点并达到相同的目的;借助此处的答案:How to get single value of List<object> 我能够弄清楚。我最终使用了一个'foreach(projectsummaryselected中的ProjectSummaryModel项){item.ProjectName}让我得到了价值。谢谢大家的帮助!!!
    • 抱歉刚刚看到你的评论。那也奏效了!并且比 foreach 循环好很多。再次感谢!!!
    【解决方案2】:

    试试这个

    <MenuItem Header="Delete Row" Command="{Binding DeleteRowCommand}" CommandParameter="{Binding SelectedItems, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"/>
    

    【讨论】:

    • 感谢@Muds 的回复,但我仍然为空。我用我刚刚在调试窗口中注意到的错误消息编辑了我的帖子。不确定这是否有帮助。
    • 我稍微修改了代码,这对我有用
    • 如果还是不行,再贴一些代码来理解
    • 我仍然为空。我发布了更多代码。这是一个小项目,所以没有太多。我包括了 DelegateCommand 类以防万一导致问题
    猜你喜欢
    • 1970-01-01
    • 2011-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-17
    • 2019-06-11
    相关资源
    最近更新 更多