【问题标题】:Row click event in WPF datagrid using mvvm使用 mvvm 在 WPF 数据网格中的行单击事件
【发布时间】:2021-01-11 14:38:16
【问题描述】:

当我单击 WPF 数据网格的一行时,我想通过使用绑定打开一个新窗口,其中包含有关单击行中的人的信息(可以更改)。我该怎么做?以及如何保存更改的信息?

提前致谢!

【问题讨论】:

  • 当我编辑答案时,您对答案的评论消失了,但我在答案中添加了“SelectedItem”属性的示例。

标签: c# wpf mvvm


【解决方案1】:

您可以在 ViewModel 中添加 SelectedItem 属性。将其绑定到 DataGrid 的 SelectedItem。现在您知道用户选择(点击了)哪个项目。

在 DataGrid 的 MouseDown 或 MouseUp 事件中,您可以使用与 DataContext 相同的 ViewModel 对象打开新窗口。这样,新窗口就知道选择了哪个项目。将新窗口的字段绑定到 ViewModel 中的 SelectedItem。

如果您正确设置了 INotifyPropertyChanged,则在新窗口中更改的值也将显示在第一个窗口的 DataGrid 中。

由于 SelectedItem 也是集合的一部分,因此您也将自动在集合中拥有更改后的值。 (我假设这就是您所说的“保存更改的信息”)。


如果绑定到 DataGrid 的集合是 Person 对象的集合,则“SelectedItem 属性”可能如下所示:

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

【讨论】:

  • xaml MouseDown 或 MouseUp 事件应该如何写?
  • 这里是一个 MouseUp 事件处理的例子。 wpf-tutorial.com/xaml/events-in-xaml
  • 我如何“将新窗口的字段绑定到 ViewModel 中的 SelectedItem”?如果您更容易回答,我可以发布我的代码。顺便感谢您之前的回答。
  • 如果您在新窗口中有一个 TextBox,您可以将 Text 属性绑定到 SelectedPerson 中的 Name 属性,如下所示:Text="{Binding SelectedPerson.Name}"
  • 它不起作用。您介意我发布我使用的其余代码,以便您检查我做错了什么吗?
【解决方案2】:

ViewModel.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

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

<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

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

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

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

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

            InitializeComponent();

            DataContext = viewModel;
            

        }
    }

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>

Window3.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();
        }
    }

我将其发布为答案,因为我无法将其添加到问题中。

【讨论】:

  • 在下面查看我的新答案。
【解决方案3】:

在 MainWindow 上,您已将 SelectedItem 绑定到“Item”。如果您在运行程序时查看输出窗口(如果您使用的是 Visual Studio),则会发现以下错误:

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

XAML 是一头野兽,所以如果绑定不起作用,请先查看那里。

您应该将 SelectedItem 绑定到 ViewModel 中的 SelectedPerson。

SelectedItem="{Binding SelectedPerson}"

要让 window3 工作,您需要将 DataContext 设置为主窗口 DataContext(视图模型)。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-18
    • 1970-01-01
    • 1970-01-01
    • 2013-11-08
    • 1970-01-01
    • 2016-05-12
    • 1970-01-01
    相关资源
    最近更新 更多