在单击DataGrid中的按钮后,我正try 在C#WPF MVVM中添加另一行.问题是,我一点击其他地方(例如,在文本框中),该行就会被添加.这意味着在我单击"添加行"按钮后,数据网格不会立即更新.

NewDocumentView.xaml

<DataGrid x:Name="DataGrid"
          AutoGenerateColumns="False"
          HorizontalAlignment="Left"
          VerticalAlignment="Top"
          Grid.Row="1"
          Margin="20,350,0,0"
          ItemsSource="{Binding Items}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Description" Binding="{Binding Description}" Width="500"/>
        <DataGridTextColumn Header="Unit" Binding="{Binding Unit}" Width="100"/>
        <DataGridTextColumn Header="Price" Binding="{Binding Price}" Width="100"/>
        <DataGridTextColumn Header="Total" Binding="{Binding Total}" Width="100"/>
        <DataGridTemplateColumn Header="Actions">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Button Content="Add Row" Command="{Binding AddItemCommand}" Width="100"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid> 

NewDocumentViewModel.cs

namespace App.MVVM.ViewModel
{
    internal class NewDocumentViewModel : ObservableObject
    {
        public ObservableCollection<Item> Items { get; set; } = new ObservableCollection<Item>();

        public RelayCommand AddItemCommand { get; set; }

        public NewDocumentViewModel()
        {
            Items = new ObservableCollection<Item>();

            AddItemCommand = new RelayCommand(o => { AddNewItem(); });
        }

        private void AddNewItem()
        {
            Items.Add(new Item());
        }
    }
}

NewDocumentView.xaml.cs

namespace App.MVVM.View
{
    public partial class NewDocumentView : UserControl
    {
        public NewDocumentView()
        {
            InitializeComponent();
            DataContext = new NewDocumentViewModel();
        }
    }
}

Item.cs

namespace App.MVVM.Model
{
    class Item : ObservableObject
    {
        private string _description;
        public string Description
        {
            get { return _description; }
            set
            {
                if (_description != value)
                {
                    _description = value;
                    OnPropertyChanged(nameof(Description));
                }
            }
        }

        private string _unit;
        public string Unit
        {
            get { return _unit; }
            set
            {
                if (_unit != value)
                {
                    _unit = value;
                    OnPropertyChanged(nameof(Unit));
                }
            }
        }

        private int _price;
        public int Price
        {
            get { return _price; }
            set
            {
                if (_price != value)
                {
                    _price = value;
                    OnPropertyChanged(nameof(Price));
                }
            }
        }

        private int _total;
        public int Total
        {
            get { return _total; }
            set
            {
                if (_total != value)
                {
                    _total = value;
                    OnPropertyChanged(nameof(Total));
                }
            }
        }
    }
}

ObservableObject.cs

namespace App.Core
{
    internal class ObservableObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

RelayCommand.cs

namespace App.Core
{
    internal class RelayCommand : ICommand
    {
        private readonly Action<object> execute;
        private readonly Func<object, bool> canExecute;

        public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
        {
            this.execute = execute;
            this.canExecute = canExecute;
        }

        public event EventHandler CanExecuteChanged
        {
            add => CommandManager.RequerySuggested += value;
            remove => CommandManager.RequerySuggested -= value;
        }

        public bool CanExecute(object parameter)
        {
            return canExecute == null || canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            execute(parameter);
        }
    }
}

我哪里做错了?如何使用按钮将新行添加到数据网格以立即更新数据网格?

推荐答案

当您将ObservableCollection绑定到数据网格的ItemsSource时,该集合中的每一项都被模板化到一行中.每行的数据上下文是一个项目.

当您绑定时,它在数据上下文中查找属性.绑定到AddItemCommand完全失败,因为Item没有AddItemCommand属性.

您可以使用relativesource在可视化树中搜索给定类型https://learn.microsoft.com/en-us/dotnet/desktop/wpf/advanced/relativesource-markupextension?view=netframeworkdesktop-4.8

如果这样做是为了查找数据网格,那么它的数据上下文继承自NewDocumentView,并且是NewDocumentViewModel.当然这就是你的指挥权所在.

不过,您需要显式地告诉它在datacontext上使用该属性,否则它将查看DatagridUI控件.

这里有一个简化的例子,希望能清楚地说明这一点.我在这里使用的是MVVM社区工具包,代码又快又脏,只是为了说明这一点.

主窗口

<Window.DataContext>
    <local:MainWindowViewmodel/>
</Window.DataContext>
<Grid>
    <DataGrid ItemsSource="{Binding Items}">
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="Actions">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Button Content="Add Row" 
Command="{Binding DataContext.AddItemCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}" Width="100"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

请注意,与相对对象绑定,我使用的是DataContext.AddItemCommand

加入时间:清华2007年01月25日下午3:33

public partial class MainWindowViewmodel : ObservableObject
{
    [ObservableProperty]
    private ObservableCollection<string> items = new ObservableCollection<string>{"A", "B" };
    
    [RelayCommand]
    private async Task AddItem()
    {
        Items.Add("X");
    }
}

当我单击该按钮时,会添加另一行.

如果你感兴趣,搜索并阅读一篇关于该工具包的适当文章可能是一个 idea ,但要简短:

该工具包使用代码生成器在分部类中生成Items属性和AddItemCommand.

Csharp相关问答推荐

当Visual Studio处于升级管理模式时,无法安装Torch运行时

使用其可能实现的基类和接口的属性的方法

程序集.加载从exe的异常

如何在NodaTime中为Instant添加一年?

为什么SignalR在每个Blazor服务器应用程序启动时最多启动8个服务器?

使用HttpResponseMessage中的嵌套列表初始化JSON

在.NET MAUI.NET 8中如何防止按钮点击时出现灰色反馈

JsonSchema.Net删除假阳性判断结果

将内置的OrderedEumable&Quot;类设置为内部类有什么好处?

为什么方法的值在SELECT方法中不会更改?

C#多键字典和TryGetValue

当空判断结果赋给变量时,为什么会出现可能空异常警告的解引用?

Azure函数-在外部启动类中生成配置时出错

我找不到ASP.NET Web应用程序(.NET框架).已 Select .NET框架项目和项模板以及此组件(&Q;)

如何在特定环境中运行dotnet测试?

如何使用ODP.NET C#设置Oracle会话时间长度限制

具有嵌套属性的IGGroup

Excel将';@';添加到具有范围的公式中

将文本从剪贴板粘贴到RichTextBox时,新文本不会在RichTextBox ForeColor中着色

.NET6最小API:操作.MapGet之后的响应