简体   繁体   English

使用 mvvm 的 WPF 数据网格中的行单击事件

[英]Row click event in WPF datagrid using mvvm

When I click on a row of WPF datagrid, I want to open a new Window that has information about a person from the clicked row (that can be changed) by using binding.当我单击 WPF 数据网格的一行时,我想通过使用绑定打开一个新的 Window,其中包含有关单击行中的人的信息(可以更改)。 How can I do it?我该怎么做? And how can I save the changed information?以及如何保存更改的信息?

Thanks in Advance!提前致谢!

You can add a SelectedItem property in the ViewModel.您可以在 ViewModel 中添加 SelectedItem 属性。 Bind that to DataGrid's SelectedItem.将其绑定到 DataGrid 的 SelectedItem。 Now you know which item the user has selected (clicked on).现在您知道用户选择了(单击)哪个项目。

In the DataGrid's MouseDown or MouseUp event you can open the new Window with the same ViewModel object as the DataContext.在 DataGrid 的 MouseDown 或 MouseUp 事件中,您可以使用与 DataContext 相同的 ViewModel object 打开新的 Window。 That way the new Window knows which item was selected.这样,新的 Window 就知道选择了哪个项目。 Bind the new Window's fields to the SelectedItem in the ViewModel.将新窗口的字段绑定到 ViewModel 中的 SelectedItem。

If you have set up the INotifyPropertyChanged correctly, the values that are changed in the new Window also will show up in the DataGrid in the first Window.如果您已正确设置 INotifyPropertyChanged,则在新 Window 中更改的值也将显示在第一个 Window 的 DataGrid 中。

Since the SelectedItem also is part of the collection, you will automatically have the changed values in the collection as well.由于 SelectedItem 也是集合的一部分,因此您也将自动在集合中拥有更改的值。 (I assume this is what you mean with "save the changed information"). (我认为这就是“保存更改的信息”的意思)。


if your collection, that is bound to the DataGrid, is a collection of Person objects, the "SelectedItem property" could look like this:如果绑定到 DataGrid 的集合是 Person 对象的集合,则“SelectedItem 属性”可能如下所示:

public Person SelectedPerson
    {
        get
        {
            return _selectedPerson;
        }
        set
        {
            _selectedPerson = value;
            PropertyChanged....
        }
    }
    private Person _selectedPerson;

ViewModel.cs视图模型.cs

namespace Procect1
{
    public class ViewModel : INotifyPropertyChanged
    {

        public ViewModel()
        {
            ListOfPeople = new ObservableCollection<Person>();

        }

        string image;
        private void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }


        private void Window2OpenExecute()
        {
            Window2 Window2 = new Window2(this);
            Window2.Show();
        }

        private void AddPhotoExecute()
        {
            foreach (Window window in Application.Current.Windows)
            {
                if (window.GetType() == typeof(Window2))
                {

                    OpenFileDialog op = new OpenFileDialog();
                    op.Title = "Select a picture";
                    op.Filter = "All supported graphics|*.jpg;*.jpeg;*.png|" +
                      "JPEG (*.jpg;*.jpeg)|*.jpg;*.jpeg|" +
                      "Portable Network Graphic (*.png)|*.png";
                    if (op.ShowDialog() == true)
                    {
                        (window as Window2).imgPhoto.Source = new BitmapImage(new Uri(op.FileName));

                        image = op.FileName;

                    }
                }
            }
        }

        private void AddPersonToListExecute()
        {
            foreach (Window window in Application.Current.Windows)
            {
                if (window.GetType() == typeof(Window2))
                {

                    ListOfPeople.Add(new Person()
                    {
                        Name = (window as Window2).textBox_FirstName.Text,
                        Surname = (window as Window2).textBox_LastName.Text,
                        IdNumber = (window as Window2).textBox_IdNumber.Text,
                        Age = (window as Window2).textBox_Age.Text,
                        Image = image
                    });

                    (window as Window2).Close();
                }
            }
        }

        private void SerializeExecute()
        {
            Stream stream = File.OpenWrite(Environment.CurrentDirectory + "\\Serialization1.xml");
            XmlSerializer people = new XmlSerializer(typeof(ObservableCollection<Person>));
            people.Serialize(stream, ListOfPeople);
            stream.Close();
        }

        private void DeSerializeExecute()
        {
            XmlSerializer deserializer = new XmlSerializer(typeof(ObservableCollection<Person>));
            TextReader textReader = new StreamReader(Environment.CurrentDirectory + "\\Serialization1.xml");
            ListOfPeople = (ObservableCollection<Person>)deserializer.Deserialize(textReader);
            textReader.Close();
        }

       
        public ICommand Window2Open { get { return new RelayCommand(Window2OpenExecute); } }
        public ICommand AddPersonToList { get { return new RelayCommand(AddPersonToListExecute); } }
        public ICommand Serialize { get { return new RelayCommand(SerializeExecute); } }
        public ICommand DeSerialize { get { return new RelayCommand(DeSerializeExecute); } }
        public ICommand AddPhoto { get { return new RelayCommand(AddPhotoExecute); } }
        public ObservableCollection<Person> ListOfPeople
        {
            get
            {
                return listOfPeople;
            }
            set
            {
                listOfPeople = value;
                OnPropertyChanged("ListOfPeople");
            }
        }

        public Person SelectedPerson
        {
            get
            {
                return _selectedPerson;
            }
            set
            {
                _selectedPerson = value;
                OnPropertyChanged(nameof(SelectedPerson));
            }
        }
        private Person _selectedPerson;
        private ObservableCollection<Person> listOfPeople;
        public event PropertyChangedEventHandler PropertyChanged;
    }
}

Person.cs个人.cs

namespace Procect1
{
    public class Person : INotifyPropertyChanged
    {
        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
                OnPropertyChanged(nameof(Name));
            }
        }

        public string Surname
        {
            get
            {
                return surname;
            }
            set
            {
                surname = value;
                OnPropertyChanged(nameof(Surname));
            }
        }

        public string IdNumber
        {
            get
            {
                return idNumber;
            }
            set
            {
                idNumber = value;
                OnPropertyChanged(nameof(IdNumber));
            }
        }

        public string Age
        {
            get
            {
                return age;
            }
            set
            {
                age = value;
                OnPropertyChanged(nameof(Age));
            }
        }

        public string Image
        {
            get
            {
                return image;
            }
            set
            {
                image = value;
                OnPropertyChanged(nameof(Image));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }

        private string name;
        private string surname;
        private string idNumber;
        private string age;
        private string image;       
    }
}

MainWindow.xaml主窗口.xaml

<Window x:Class="Procect1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Procect1"
        mc:Ignorable="d"
        Title="Lista pacjentów"  Height="450" Width="800">
    <Window.DataContext>
        <local:ViewModel/>
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <!--<RowDefinition Height="auto"  />-->
            <!--<RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>-->
        </Grid.RowDefinitions>
        <DataGrid  Name="listView" MouseUp="listView_MouseUp" ItemsSource="{Binding ListOfPeople}" AutoGenerateColumns="False" SelectedItem="{Binding Index}">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding  Name, UpdateSourceTrigger=PropertyChanged}" Header="Imię" />
                <DataGridTextColumn Binding="{Binding Surname}" Header="Nazwisko" />
                <DataGridTextColumn Binding="{Binding IdNumber}" Header="Pesel"  />
                <DataGridTextColumn  Binding="{Binding Age}" Header="Wiek" />
                <DataGridTemplateColumn Header="Zdjęcie" Width=" 100">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Image Source="{Binding Image}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
        <Canvas>
            <Button Canvas.Right="20" Canvas.Top="30" Height="50" Width="80" FontSize="18" Command="{Binding Window2Open}">Dodaj</Button>
            <Button Canvas.Right="20" Canvas.Top="100" Height="50" Width="80" FontSize="18" Command="{Binding Serialize}">Serializuj</Button>
            <Button Canvas.Right="20" Canvas.Top="170" Height="50" Width="80" FontSize="18" Command="{Binding DeSerialize}">Załaduj</Button>
        </Canvas>
    </Grid>
</Window>

MainWindow.cs主窗口.cs

public partial class MainWindow : Window
    {
        
        public MainWindow( )
        {
            InitializeComponent();
            
        }

        private void listView_MouseUp(object sender, MouseButtonEventArgs e)
        {
            Window3 window3 = new Window3();
            window3.Show();
        }
    }

Window2.xaml Window2.xaml

<Window x:Class="Procect1.Window2"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Procect1"
        mc:Ignorable="d"
        Title="Dane Pacjenta" Height="600" Width="500">
    <Canvas>
        <Label Canvas.Left="20" Canvas.Top="20" FontSize="24">Imię</Label>
        <TextBox x:Name="textBox_FirstName" Canvas.Left="190" Canvas.Top="30" Height="28" Width="200" ></TextBox>
        <Label Canvas.Left="20" Canvas.Top="100" FontSize="24">Nazwisko</Label>
        <TextBox x:Name="textBox_LastName" Canvas.Left="190" Canvas.Top="110" Height="28" Width="200"></TextBox>
        <Label Canvas.Left="20" Canvas.Top="180" FontSize="24">Pesel</Label>
        <TextBox x:Name="textBox_IdNumber" Canvas.Left="190" Canvas.Top="190" Height="28" Width="200"></TextBox>
        <Label Canvas.Left="20" Canvas.Top="260" FontSize="24">Wiek</Label>
        <TextBox x:Name="textBox_Age" Canvas.Left="190" Canvas.Top="270" Height="28" Width="200"></TextBox>
        <Label Canvas.Left="20" Canvas.Top="340" FontSize="24">Zdjęcie</Label>
        <Image Name="imgPhoto" Canvas.Left="190" Canvas.Top="350" Height="120" Width="150"></Image>
        <Button Canvas.Right="20" Canvas.Top="400" FontSize="16" Command="{Binding AddPhoto}" >Dodaj zdjęcie</Button>
        <Button Canvas.Left="250" Canvas.Bottom="20" Height="40" Width="80" FontSize="24" Command="{Binding AddPersonToList}">Zapisz</Button>
    </Canvas>
</Window>

MainWindow2.cs MainWindow2.cs

public partial class Window2 : Window
    {
        public Window2(ViewModel viewModel)
        {

            InitializeComponent();

            DataContext = viewModel;
            

        }
    }

Window3.xaml Window3.xaml

<Window x:Class="Procect1.Window3"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Procect1"
        mc:Ignorable="d"
        Title="Dane Pacjenta" Height="600" Width="500">
    <Window.DataContext>
        <local:ViewModel/>
    </Window.DataContext>
    <Canvas>
        <Label Canvas.Left="20" Canvas.Top="20" FontSize="24">Imię</Label>
        <TextBox x:Name="textBox_FirstName" Text="{Binding SelectedPerson.Name}" Canvas.Left="190" Canvas.Top="30" Height="28" Width="200" ></TextBox>
        <Label Canvas.Left="20"  Canvas.Top="100" FontSize="24">Nazwisko</Label>
        <TextBox x:Name="textBox_LastName" Text="{Binding SelectedPerson.Surname}" Canvas.Left="190" Canvas.Top="110" Height="28" Width="200"></TextBox>
        <Label Canvas.Left="20" Canvas.Top="180" FontSize="24">Pesel</Label>
        <TextBox x:Name="textBox_IdNumber" Text="{Binding SelectedPerson.IdNumber}" Canvas.Left="190" Canvas.Top="190" Height="28" Width="200"></TextBox>
        <Label Canvas.Left="20" Canvas.Top="260" FontSize="24">Wiek</Label>
        <TextBox x:Name="textBox_Age" Text="{Binding SelectedPerson.Age}" Canvas.Left="190" Canvas.Top="270" Height="28" Width="200"></TextBox>
        <Label Canvas.Left="20" Canvas.Top="340" FontSize="24">Zdjęcie</Label>
        <Image Name="imgPhoto" Source="{Binding SelectedPerson.Image}" Canvas.Left="190" Canvas.Top="350" Height="120" Width="150"></Image>
        <Button Canvas.Right="20" Canvas.Top="400" FontSize="16" Command="{Binding AddPhoto}" >Dodaj zdjęcie</Button>
        <Button Canvas.Left="250" Canvas.Bottom="20" Height="40" Width="80" FontSize="24">Zapisz</Button>
    </Canvas>
</Window>

In Window3.cs I haven't added any code.Window3.cs 中我没有添加任何代码。

RylayCommand.cs RylayCommand.cs

public class RelayCommand : ICommand
    {
        private readonly Func<bool> _canExecute;
        private readonly Action _execute;

        public RelayCommand(Action execute)
            : this(execute, null)
        {
        }

        public RelayCommand(Action execute, Func<bool> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");
            _execute = execute;
            _canExecute = canExecute;
        }

        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (_canExecute != null)
                    CommandManager.RequerySuggested += value;
            }
            remove
            {
                if (_canExecute != null)
                    CommandManager.RequerySuggested -= value;
            }
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute();
        }

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

I post it as an answer because I couldn't add it to the question.我将其发布为答案,因为我无法将其添加到问题中。

On MainWindow you have bound the SelectedItem to "Item".在 MainWindow 上,您已将 SelectedItem 绑定到“Item”。 If you look at the Output window (if you are using Visual Studio) when you are running the program, you find following error:如果您在运行程序时查看 Output window(如果您使用的是 Visual Studio),您会发现以下错误:

System.Windows.Data Error: 40 : BindingExpression path error: 'Index' property not found on 'object' ''ViewModel'

XAML is a very quite beast, so look there first if the bindings doesn't work. XAML 是一个非常野兽,所以如果绑定不起作用,请先查看那里。

You should bind the SelectedItem to the SelectedPerson in the ViewModel.您应该将 SelectedItem 绑定到 ViewModel 中的 SelectedPerson。

SelectedItem="{Binding SelectedPerson}"

To get the window3 to work, you need to set the DataContext to the main windows DataContext (the view model).要让 window3 工作,您需要将 DataContext 设置为主 windows DataContext(视图模型)。

        Window3 window3 = new Window3();
        window3.DataContext = this.DataContext;
        window3.Show();

I did solve a simelar propblem using the Behaviours Libary.我确实使用行为库解决了一个类似的问题。 First Make sure you have the Nuget package: "Microsoft.Xaml.Behaviors.Wpf" installed.首先确保您安装了 Nuget package:“Microsoft.Xaml.Behaviors.Wpf”。

xmlns:i="http://schemas.microsoft.com/xaml/behaviors"

<DataGrid>
    <i:Interaction.Triggers>
        <i:EventTrigger
            EventName="MouseUp">
            <i:InvokeCommandAction
                Command="{Binding OpenWindowCommand}"
                CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}, Path=SelectedItem}">
            </i:InvokeCommandAction>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</DataGrid>

Hope this snippet helps.希望这个片段有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM