WPF MVVM: обновить сетку данных на основе выбранного элемента другой сетки данных - PullRequest
0 голосов
/ 30 октября 2019

Диаграмма классов Я занимаюсь разработкой приложения wpf с использованием шаблона MVVM. Я хочу обновить вторую сетку данных на основе выбора первой сетки данных, и если есть какие-либо изменения в Itemource второй сетки данныхЯ хочу обновить это изменение, пока сохраняется выбор первого датарида. Кто-нибудь может мне помочь с этим.

Необходимость более или менее похожа на это DataGrid SelectionChanged MVVM . Но всякий раз, когда происходит обновление в первой коллекции сетки данных, данные во второй таблице данных должны обновляться для выбранного элемента первой сетки данных.

O8Lwl.png

1 Ответ

0 голосов
/ 30 октября 2019

На основе ваших комментариев я создал минимальный пример, который показывает привязку. Я надеюсь, что это то, что вы искали.

MainWindow.xaml и код позади

<Window x:Class="WpfApp1.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"
        mc:Ignorable="d"
        Title="MainWindow" Height="400" Width="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="300*"/>
            <RowDefinition Height="50"/>
        </Grid.RowDefinitions>
        <DataGrid Grid.Column="0" Grid.Row="0" Width="Auto" ItemsSource="{Binding DeviceList}" SelectedItem="{Binding SelectedDevice}" AutoGenerateColumns="True" />
        <DataGrid Grid.Column="1" Grid.Row="0" Width="Auto" DataContext="{Binding SelectedDevice}" ItemsSource="{Binding Path=FaultList}" AutoGenerateColumns="True"/>
        <Button Content="Trigger DataGrid 1 update" Grid.Column="0" Grid.Row="1" Margin="10,10,10,10" Width="Auto" Height="Auto" Click="Button_Click"/>
    </Grid>
</Window>

// Code behind in MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        private MainViewModel vm;

        public MainWindow()
        {
            InitializeComponent();
            vm = new MainViewModel();
            DataContext = vm;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            vm.AddDevice();
        }
    }
}

MainViewModel и MainModel

using System;
using System.Collections.ObjectModel;
using System.Linq;
using WpfApp1.ViewModels;

namespace WpfApp1
{
    public class MainViewModel : ViewModelBase<MainModel>
    {
        private DeviceViewModel selectedDevice;
        public ObservableCollection<DeviceViewModel> DeviceList
        {
            get { return Model.DeviceList; }
        }
        public DeviceViewModel SelectedDevice
        {
            get { return selectedDevice; }
            set
            {
                selectedDevice = value;
                RaisePropertyChanged("SelectedDevice");
            }
        }
        public MainViewModel() : base(new MainModel())
        {

        }

        public void AddDevice()
        {
            int rnd = new Random().Next(1, 100);
            if (!Model.DeviceList.Any(x => x.Name == $"Device_{rnd}"))
                Model.DeviceList.Add(new DeviceViewModel($"Device_{rnd}"));

            RaisePropertyChanged("DeviceList");
        }
    }
}

using System.Collections.ObjectModel;
using WpfApp1.ViewModels;

namespace WpfApp1
{
    public class MainModel
    {
        private ObservableCollection<DeviceViewModel> deviceList;

        public ObservableCollection<DeviceViewModel> DeviceList
        {
            get { return deviceList; }
            set { deviceList = value; }
        }

        public MainModel()
        {
            deviceList = new ObservableCollection<DeviceViewModel>();
        }
    }
}

DeviceViewModel.cs и Device.cs

using System.Collections.ObjectModel;
using WpfApp1.Models;

namespace WpfApp1.ViewModels
{
    public class DeviceViewModel : ViewModelBase<Device>
    {
        private Fault selectedFault = null;

        public string Name
        {
            get { return Model.Name; }
            set
            {
                Model.Name = value;
                RaisePropertyChanged("Name");
            }
        }
        public string SerialNumber
        {
            get { return Model.Id.ToString(); }
        }
        public ObservableCollection<FaultViewModel> FaultList
        {
            get { return Model.FaultList; }
        }
        public Fault SelectedFault
        {
            get { return selectedFault; }
            set
            {
                selectedFault = value;
                RaisePropertyChanged("SelectedFault");
            }
        }

        public DeviceViewModel() : base(new Device())
        {
            FaultList.CollectionChanged += FaultList_CollectionChanged;
        }

        public DeviceViewModel(string name) : this()
        {
            Name = name;

            for (int i = 0; i < 5; i++)
                Model.FaultList.Add(new FaultViewModel() { Name = $"Fault_{i} of {name}" });

            RaisePropertyChanged("FaultList");
        }

        private void FaultList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            RaisePropertyChanged("FaultList");
        }
    }
}


using System;
using System.Collections.ObjectModel;

namespace WpfApp1.Models
{
    public class Device
    {
        private string name = "";
        private Guid id;
        private ObservableCollection<FaultViewModel> faultList;

        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public Guid Id
        {
            get { return id; }
            set { id = value; }
        }

        public ObservableCollection<FaultViewModel> FaultList
        {
            get { return faultList; }
            set { faultList = value; }
        }

        public Device()
        {
            this.id = new Guid();
            this.faultList = new ObservableCollection<FaultViewModel>();
        }

        public Device(string name) : this()
        {
            this.name = name;
        }
    }
}

FaultViewModel.cs и Fault.cs

using WpfApp1.Models;

namespace WpfApp1
{
    public class FaultViewModel : ViewModelBase<Fault>
    {
        public string Name
        {
            get { return Model.FaultName; }
            set
            {
                Model.FaultName = value;
                RaisePropertyChanged("Name");
            }
        }
        public string Id
        {
            get { return Model.FaultId.ToString(); }
        }

        public FaultViewModel() : base(new Fault())
        {

        }
    }
}

using System;

namespace WpfApp1.Models
{
    public class Fault
    {
        private Guid faultId;
        private string faultName;

        public Guid FaultId
        {
            get { return faultId; }
            set { faultId = value; }
        }

        public string FaultName
        {
            get { return faultName; }
            set { faultName = value; }
        }


        public Fault()
        {
            this.faultId = new Guid();
        }
    }
}

Последнее, но не менее важное: ViewModelBase.cs

using System.ComponentModel;

namespace WpfApp1
{
    public class ViewModelBase<T> : INotifyPropertyChanged
    {
        T model;
        public T Model { get { return model; } }

        public ViewModelBase(T model)
        {
            this.model = model;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null && !string.IsNullOrEmpty(propertyName))
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Если вы запустите приложение, вы можете нажатькнопка, которая имитирует обновление списка устройств в коде позади. Затем вы можете выбрать устройство, и вторая DataGrid покажет FaultList этого устройства.


Старый ответ

Обновление: Похожиек вашим комментариям и диаграмме классов:

Первое:

Я вижу только один список в классе Device. Я предполагаю, что это источник для первой DataGrid? Таким образом, вы хотите отобразить свойства объектов типа Fault в 1-й DataGrid. Если это так, где находится источник для второй DataGrid? Или вам не хватает свойства Collection в классе Fault?

Second:

Для привязки данных вы должны использовать ObservableCollection , который реализует INotifyCollectionChanged. Вы не можете использовать Список <>.

Третье:

Не видя ваш код, я могу только догадываться, что происходит не так. Давайте предположим, что класс Device содержит ObservableCollection<Fault> FaultList, а класс Fault содержит ObservableCollection<string> FaultDetails. DataGrid 1 отображает список неисправностей, и если вы выберете одну из них, DataGrid 2 отображает некоторые подробности неисправностей. В вашей DeviceViewModel у вас будет ObservableCollection<Fault> FaultList и свойство Fault SelectedFault. Теперь FaultList должен быть ItemSource первой DataGrid, а SelectedFault должен быть связан со свойством DataGrid.SelectedItem. ItemSource Datagrid 2 должен быть FaultDetails, а DataContext должен быть SelectedFault. Возможно, вам нужно распространять информацию об изменении свойства.

Я не проверял это! Минимальный исполняемый пример, который показывает, что проблема была бы отличной.


Старый ответ:

Прошло много времени с тех пор, как я написал свое последнее приложение WPF, но оновозможно, вы либо инициируете событие NotifyPropertyChanged для 2-й DataGrid в неправильном месте, либо вы вызываете его для неправильного свойства.

DataGrid имеет событие SelectionChanged. Возможно, вы сможете получить доступ к своей виртуальной машине оттуда и вызвать правильное событие PropertyChanged для своей второй DataGrid.

...