WPF MVVM 绑定命令到 Datagrid

如何解决WPF MVVM 绑定命令到 Datagrid

我正在创建一个包含 2 个窗口的 WPF 模具应用程序:带有 DataGrid 的 MainWindow 和允许添加/编辑模具的 AddEditWindow。

我有一个位于 DataGrid 的 TemplateColumn 中的 EditButton:

<DataGridTemplateColumn Width="Auto">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                                <Button Width="150" 
                                    Height="40" 
                                    BorderThickness="2" 
                                    BorderBrush="DarkRed"
                                    Background="Red" 
                                    Foreground="White" 
                                    Content="Edit" 
                                    Name="BtnEdit"                                   
                                    CommandParameter="{Binding}"
                                    Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}},Path=DataContext.AddEditWindowCommand}">
                                </Button>
                            </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>

添加编辑窗口命令:

public ICommand AddEditWindowCommand { get; }

        private bool CanAddEditWindowCommandExecute(object SelectedRow) => true;

        private void OnAddEditWindowCommandExecuted(object SelectedRow)
        {
            
            AddEditWindow window = new AddEditWindow();
            window.Show();
        }

我想将 DataContext 传递给 AddEditWindowViewModel。在代码隐藏中,我可以做这样的事情:

private void BtnEdit_Click(object sender,RoutedEventArgs e)
        {
            AddEditWindow addEditWindow = new AddEditWindow((sender as Button).DataContext as Molds);
            addEditWindow.Show();
        }

然后像这样检索它AddEditWindow:

private Molds _currentMold = new Molds();
        public GamesEdit(Molds selectedMold)
        {
            InitializeComponent();
            if (selectedMold != null)
            {
                _currentMold = selectedMold;
                              
            }

            DataContext = _currentMold;

但在 MVVM 中我不能。那么,有没有办法在不破坏 MVVM 模式的情况下做到这一点?

附言由于我是 MVVM 的新手,我非常感谢详细的解释。

更新:

主窗口视图模型:

internal class MainWindowViewModel : ViewModel
    {
      
        #region Variables
       
        #region Textblocks for search

        private Molds newMolds { get; set; } = new Molds();
        public string TxtType
        {
            get => newMolds.Type;
            set => newMolds.Type = value;
        }

        public string TxtName
        {
            get => newMolds.Name;
            set => newMolds.Name = value;
        }

        public string TxtKus
        {
            get => newMolds.Kus;
            set => newMolds.Kus = value;
        }

        #endregion

        #region AllMolds

        private ObservableCollection<Molds> allMolds = new ObservableCollection<Molds>(ApplicationContext.GetContext().Molds.ToList());
        public ObservableCollection<Molds> AllMolds
        {
            get => allMolds; 
            set => allMolds = value;           
        }

        #endregion

        #region FilteredMolds

        private ObservableCollection<Molds> filteredMolds = new ObservableCollection<Molds>(ApplicationContext.GetContext().Molds.ToList());
        public ObservableCollection<Molds> FilteredMolds
        {
            get
            {               
                filteredMolds = AllMolds;              
                var currentfilteredmolds = new List<Molds>(filteredMolds);
                if (TxtName != null)
                    currentfilteredmolds = currentfilteredmolds.Where(p => p.Name.ToLower().Contains(TxtName.ToLower())).ToList();
                if (TxtType != null)
                    currentfilteredmolds = currentfilteredmolds.Where(p => p.Type.ToLower().Contains(TxtType.ToLower())).ToList();
                if (TxtKus != null)
                    currentfilteredmolds = currentfilteredmolds.Where(p => p.Kus.ToLower().Contains(TxtKus.ToLower())).ToList();
                return new ObservableCollection<Molds>(currentfilteredmolds);
            }
            
            set => filteredMolds = value;
        }

        #endregion

        
        #endregion

        #region Commands

        #region CloseApplicationCommand
        public ICommand CloseApplicationCommand { get; }

        private bool CanCloseApplicationCommandExecute(object p) => true;

        private void OnCloseApplicationCommandExecuted(object p)
        {
            Application.Current.Shutdown();
        }
        #endregion

        #region SearchCommand

        public ICommand SearchCommand { get; }

        private bool CanSearchCommandExecute(object p) => true;

        private void OnSearchCommandExecuted(object p)
        {            
            OnPropertyChanged("FilteredMolds");
        }

        #endregion

        #region Open AddEditWindowCommand
        public ICommand AddEditWindowCommand { get; }

        private bool CanAddEditWindowCommandExecute(object SelectedRow) => true;

        private void OnAddEditWindowCommandExecuted(object SelectedRow)
        {
            
            AddEditWindow window = new AddEditWindow();
            window.Show();
        }
        #endregion

        #region DeleteMoldCommand

        public ICommand DeleteMoldCommand { get; }

        private bool CanDeleteMoldCommandExecute(object SelectedItems)
        {
            if (SelectedItems != null) return true; else return false;           
        }
       
        private void OnDeleteMoldCommandExecuted(object SelectedItems)
        {
            System.Collections.IList items = (System.Collections.IList)SelectedItems;
            var moldsforRemoving = items?.Cast<Molds>().ToList();

            if (MessageBox.Show($"You want to remove the following {moldsforRemoving.Count()} molds?","Attention",MessageBoxButton.YesNo,MessageBoxImage.Question) == MessageBoxResult.Yes)
            {
                try
                {
                    ApplicationContext.GetContext().Molds.RemoveRange(moldsforRemoving);
                    ApplicationContext.GetContext().SaveChanges();
                    MessageBox.Show("Data deleted successfully.","Data deletion",MessageBoxButton.OK,MessageBoxImage.Information);
                    AllMolds = new ObservableCollection<Molds>(ApplicationContext.GetContext().Molds.ToList());
                    OnPropertyChanged("FilteredMolds");
                }

                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message.ToString(),"Error",MessageBoxImage.Error);
                }
            }
        }

        #endregion

        #region DragMoveCommand

        public ICommand DragMoveCommand { get; }

        private bool CanDragMoveCommandExecute(object p) => true;

        private void OnDragMoveCommandExecuted(object p)
        {
            Application.Current.MainWindow.DragMove();
        }

        #endregion

        #endregion

        public MainWindowViewModel()
        {
            #region Command Samples

            CloseApplicationCommand = new LamdaCommand(OnCloseApplicationCommandExecuted,CanCloseApplicationCommandExecute);
            SearchCommand = new LamdaCommand(OnSearchCommandExecuted,CanSearchCommandExecute);
            AddEditWindowCommand = new LamdaCommand(OnAddEditWindowCommandExecuted,CanAddEditWindowCommandExecute);
            DeleteMoldCommand = new LamdaCommand(OnDeleteMoldCommandExecuted,CanDeleteMoldCommandExecute);
            DragMoveCommand = new LamdaCommand(OnDragMoveCommandExecuted,CanDragMoveCommandExecute);


            #endregion

            #region Variable Samples for searching

            TxtName = null;
            TxtKus = null;
            TxtType = null;

            #endregion
          
        }
    }

AddEditWindowViewModel

internal class AddEditWindowViewModel : ViewModel
    {
        #region Variables     


        private Molds _currentMold = new Molds();
    

        #endregion

        #region Commands

        #region CloseWindowCommand
        public ICommand CloseWindowCommand { get; }

        private bool CanCloseWindowCommandExecute(object p) => true;

        private void OnCloseWindowCommandExecuted(object p)
        {
            Application.Current.Windows[1].Close();           
        }
        #endregion

        #region DragMoveAddEditWindowCommand

        public ICommand DragMoveAddEditWindowCommand { get; }

        private bool CanDragMoveAddEditWindowCommandExecute(object p) => true;

        private void OnDragMoveAddEditWindowCommandExecuted(object p)
        {
            Application.Current.Windows[1].DragMove();
        }

        #endregion

        #endregion

        public AddEditWindowViewModel()
        {
            
            #region Command samples

            CloseWindowCommand = new LamdaCommand(OnCloseWindowCommandExecuted,CanCloseWindowCommandExecute);
            DragMoveAddEditWindowCommand = new LamdaCommand(OnDragMoveAddEditWindowCommandExecuted,CanDragMoveAddEditWindowCommandExecute);

            #endregion

        }
    }

我使用 将它们连接到窗口:

<Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>

同样适用于 AddEditWindowViewModel。

DataGrid 绑定:

<DataGrid x:Name="DGridMolds" 
                  AutoGenerateColumns="False" 
                  IsReadOnly="True" 
                  Foreground="White" 
                  BorderBrush="White" 
                  Background="#2b2a38"
                  Grid.Column="1"
                  Grid.Row="1"
                  ItemsSource="{Binding Path=FilteredMolds}"
                  >

AddEditWindow.Xaml:

<Window.DataContext>
        <vm:AddEditWindowViewModel/>
    </Window.DataContext>

    <Border Background="#2f2e3c" 
            CornerRadius="10">

        <Border.InputBindings>
            <MouseBinding Command="{Binding DragMoveAddEditWindowCommand}" MouseAction="LeftClick"/>
        </Border.InputBindings>

        <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition/>
            <RowDefinition Height="30"/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="30"/>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition Width="30"/>
        </Grid.ColumnDefinitions>

            <StackPanel Grid.Column="1" Grid.Row="1" Orientation="Vertical">
                <TextBlock Text="Add" FontSize="22" Foreground="White" HorizontalAlignment="Center" Margin="0,30,0"/>
                <TextBox Foreground="White" Text="{Binding Type,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Margin="5,35,5,5" materialDesign:HintAssist.Hint="Type"/>
                <TextBox Foreground="White" Text="{Binding Name,UpdateSourceTrigger=PropertyChanged}" Margin="5" materialDesign:HintAssist.Hint="Name"/>
                <TextBox Foreground="White" Text="{Binding Kus,UpdateSourceTrigger=PropertyChanged}" Margin="5" materialDesign:HintAssist.Hint="Kus"/>

解决方法

在代码隐藏中,我可以做这样的事情:

仔细查看您的 XAML。
您在 CommanParameter 属性中设置了绑定。
绑定实例为空 - 这意味着绑定发生在指定它的元素的 DataContext 上。
因此,在命令参数中,您将获得此数据上下文。

        private void OnAddEditWindowCommandExecuted(object SelectedRow)
        {
            AddEditWindow window = new AddEditWindow()
                    {DataContext = SelectedRow};
            window.Show();
        }

那么,有没有办法在不破坏 MVVM 模式的情况下做到这一点?

你已经破坏了 MVVM。
不允许 ViewModel 与 UI 元素一起使用。
ViewModel 甚至不需要知道正在使用什么类型的 View:WPF、Forms 或 Console。
而你创造了窗户!
对于 MVVM 概念来说,这是不可接受的

与在主要问题中显示更详细代码有关的补充:

我无法理解您代码的逻辑。 因此,我会在了解您的意图的情况下写下该措施。

AddEditWindowViewModel 类 - 设计用于编辑和/或添加项目的逻辑。 但随后他必须获取此元素并将其提供在他的属性中,以便他可以创建用于编辑的 GUI。

应该是这样的:

namespace MoldsApp
{
    public class AddEditWindowViewModel : ViewModel
    {
        public Molds CurrentMold { get; }

        // Constructor called to edit an entity
        public AddEditWindowViewModel(Molds currentMold)
        {
            CurrentMold = currentMold;
        }

        //Constructor called to create and edit an entity
        public AddEditWindowViewModel()
            : this(new Molds())
        {
        }
    }
}

此外,您的 DataContext 设置不正确。
通过在 XAML 中创建它,您无法为 ViewModel 的此实例设置数据。
因此,在 XAML 中,您可以实例化仅在其设计时使用的 ViewModel。
对于设计时 DataContext,请使用 d: 前缀。

    <d:Window.DataContext>
        <vm:MainWindowViewModel/>
    </d:Window.DataContext>

有了这些变化,项目编辑命令应该是这样的:

    private void OnAddEditWindowCommandExecuted(object SelectedRow)
    {
        AddEditWindow window = new AddEditWindow()
        {
             DataContext =  new AddEditWindowViewModel((Molds)SelectedRow)
        };
        window.Show();
    }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res