簡體   English   中英

使用 mvvm 的 WPF 數據網格中的行單擊事件

[英]Row click event in WPF datagrid using mvvm

當我單擊 WPF 數據網格的一行時,我想通過使用綁定打開一個新的 Window,其中包含有關單擊行中的人的信息(可以更改)。 我該怎么做? 以及如何保存更改的信息?

提前致謝!

您可以在 ViewModel 中添加 SelectedItem 屬性。 將其綁定到 DataGrid 的 SelectedItem。 現在您知道用戶選擇了(單擊)哪個項目。

在 DataGrid 的 MouseDown 或 MouseUp 事件中,您可以使用與 DataContext 相同的 ViewModel object 打開新的 Window。 這樣,新的 Window 就知道選擇了哪個項目。 將新窗口的字段綁定到 ViewModel 中的 SelectedItem。

如果您已正確設置 INotifyPropertyChanged,則在新 Window 中更改的值也將顯示在第一個 Window 的 DataGrid 中。

由於 SelectedItem 也是集合的一部分,因此您也將自動在集合中擁有更改的值。 (我認為這就是“保存更改的信息”的意思)。


如果綁定到 DataGrid 的集合是 Person 對象的集合,則“SelectedItem 屬性”可能如下所示:

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

視圖模型.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;
    }
}

個人.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;       
    }
}

主窗口.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>

主窗口.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();
        }
    }

我將其發布為答案,因為我無法將其添加到問題中。

在 MainWindow 上,您已將 SelectedItem 綁定到“Item”。 如果您在運行程序時查看 Output window(如果您使用的是 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 設置為主 windows DataContext(視圖模型)。

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

我確實使用行為庫解決了一個類似的問題。 首先確保您安裝了 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>

希望這個片段有幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM