MVVM C#​​ WPF - UI 在更改 observablecollection 中的项目时不更新

MVVM C# WPF - UI not updating when changing items in observablecollection

两天来我一直在查看有关此问题的 Whosebug 帖子,但我似乎无法理解为什么我的代码无法正常工作

当我更改 ObservableCollection 中的项目时,我似乎无法更新 UI 中的数据网格。

我知道 ObservableCollection 不会在其中的项目发生更改时触发 PropertyChanged 事件。

似乎其他人已经通过向模型添加 INotifyPropertyChanged 并在更改 属性 时调用 OnPropertyChanged 成功地做到了这一点。我已经实施了这个并且我检查了 PropertyChanged 事件是否正在发生。

UI 在向 collection 添加新项目时更新。

我意识到这可能是一个线程问题,但我真的不明白如何检查或修复它。

我对编程还很陌生,并试图了解 MVVM。

有什么建议吗?

型号:

public class ModelObj : INotifyPropertyChanged
{
    public string Name { get; set; }
    public string IpAddress { get; set; }

    private DateTime timer;

    public DateTime Timer
    {
        get { return timer; }
        set
        {
            timer = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

ViewModel:

public class MainViewModel : ViewModelBase
{
    public ObservableCollection<ModelObj> ModelObjects { get; } = new ObservableCollection<ModelObj>();

    private IUdpDataService _udpDataService;

    public MainViewModel(IUdpDataService udpDataService)
    {
        _udpDataService = udpDataService;
    }

    public void StartUdpDataService()
    {
        _udpDataService.StartBroadCasting();
        _udpDataService.ReceivedDataEvent += ParseReceivedData;
    }

    private void ParseReceivedData(string receivedData)
    {
        // This object contains all the information in the received data packet. 
        UdpPacket udpPacket = new UdpPacket(receivedData);

        // This object only contains the object name, IpAddress and a time variable.
        ModelObj modelObj = new ModelObj
        {
            Name = udpPacket.Name,
            IpAddress = udpPacket.IpEthernet,
            Timer = DateTime.Now,
        };

        App.Current.Dispatcher.Invoke((Action)delegate
        {
            UpdateList(modelObj);
        });
    }

    private void UpdateList(ModelObj modelObj)
    {
        var testObj = ModelObjects.FirstOrDefault(x => x.Name == modelObj.Name);
        if (testObj != null)
        {
            testObj = modelObj
        }
        else
        {
            ModelObjects.Add(modelObj);
            testObj = modelObj;
        }
    }
}

查看:

public partial class MainWindow : Window
{
    private MainViewModel _viewModel;

    public MainWindow(MainViewModel viewModel)
    {
        InitializeComponent();
        _viewModel = viewModel;
        DataContext = _viewModel;
        Loaded += MainWindow_Loaded;
    }

    private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        _viewModel.StartUdpDataService();
    }

    protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
    {
            Settings.Default.Save();
            base.OnClosing(e);
    }
}

XAML:

     <DataGrid Grid.Row="0" ItemsSource="{Binding Path=ModelObjects}"
              IsReadOnly="True"
              Background="white"
              RowHeaderWidth ="0" 
              AutoGenerateColumns="False">

        <DataGrid.Columns>
            <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="auto" MinWidth="150"/>
            <DataGridTextColumn Header="IP address" Binding="{Binding IpAddress}" Width="*"/>
            <DataGridTextColumn Header="Timer" Binding="{Binding Timer, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
        </DataGrid.Columns>
    </DataGrid>

您应该设置现有对象的 Timer 属性:

private void UpdateList(ModelObj modelObj)
{
    var testObj = ModelObjects.FirstOrDefault(x => x.Name == modelObj.Name);
    if (testObj != null)
    {
        testObj.Timer = modelObj.Timer
    }
    else
    {
        ModelObjects.Add(modelObj);
    }
}

您当前正在获取对现有对象的引用,然后将保存此引用的 testObj 变量设置为对传递给 [=14= 的新 ModelObj 对象的引用] 方法。这不会更新 the ModelObjects 集合中对象的 Timer 属性。

testObj = modelObj

没有效果。您只需将值放入变量即可。致电

    if (testObj != null)
    {
        ModelObjects.Replace(testObj,modelObj)
    }
    else
    {
        ModelObjects.Add(modelObj);
    }

如果您替换整个对象,则根本不需要实施 INotifyPropertyChanged