在单击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相关问答推荐

找不到网址:https://localhost:7002/Category/Add?区域= Admin.为什么我的URL是这样生成的?area = Admin而不是/Admin/

为什么Blazor值在更改后没有立即呈现?

Select Many和默认IfEmpty内部Select Many错误工作

如何定义EFCore中的多个穿透

从c#列表中删除额外的对象&对象&>从ASP.NET WebForm返回json响应

需要在重新启动ApplicartionPool或IIS后启动/唤醒API的帮助

在命名管道上使用GRPC ASP.NET核心时如何配置命名管道权限

使用Orleans进行的单元测试找不到接口的实现

MS Graph v5.42.0:在寻呼消息时更改页面大小

使用泛型可空类实现接口

具有可空类型的C#NOTNULL约束具有意外行为

当使用Dapper映射DBNull时,我可以抛出异常吗?

MSTest--将消息直接写入StdOut和使用TestContext有什么不同?

为什么C#/MSBuild会自发地为不同的项目使用不同的输出路径?

C#System.Commandline:如何向命令添加参数以便向其传递值?

为什么我可以在注册表编辑器中更改值,但不能在以管理员身份运行的C#表单应用程序中更改?

如何使ExecuteAsync异步运行

使用';UnityEngineering.Random.Range()';的IF语句仅适用于极高的最大值

C#、Visual Studio代码、调试器、错误处理变量请求.未知错误:0x80131502,

Firefox中的MudBlazor DataGrid单元格溢出