MVVM C#WPF - 更改observablecollection中的项目时UI未更新

时间:2018-04-20 12:19:52

标签: c# wpf user-interface mvvm inotifypropertychanged

我一直在关注这个问题的Stackoverflow帖子两天了,我似乎无法理解为什么我的代码无效

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

我知道ObservableCollection如果其中的项目发生变化,则不会触发PropertyChanged事件。

似乎其他人已成功完成此操作,方法是将INotifyPropertyChanged添加到模型中,并在更改属性时调用OnPropertyChanged。我已经实现了这一点,并且我已经检查了PropertyChanged事件是否已经结束。

在向集合添加新项目时,UI会更新。

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

我对编程很新,并试图围绕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));
    }
}

视图模型:

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>

2 个答案:

答案 0 :(得分:1)

您应该设置现有对象的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变量设置为对传递给ModelObj方法的新UpdateList对象的引用。这不会更新Timer ModelObjects集合中对象的the属性。

答案 1 :(得分:0)

testObj = modelObj

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

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

如果你替换整个对象,根本不需要实现INotifyPropertyChanged