【问题标题】:MVVM/WPF UI not update when executing method second time第二次执行方法时,MVVM/WPF UI 不更新
【发布时间】:2020-06-26 12:59:40
【问题描述】:

即使我应用了 INotifyPropertyChange,当我的属性更改时,我的 UI 也无法更新。当我第一次运行代码时,它显示正确并且 UI 已更新。在调试时,我可以看到新值被设置为视图模型的字符串,并且 OnPropertChange 事件被触发,它只是在 UI 中没有发生任何事情。下面的代码将按事件顺序排列。作为额外信息,我在第一次和第二次都使用相同的代码来更新视图模型。

    public partial class Transaktioner : Window
    {
        ViewModelCommon.ViewModel view = new ViewModelCommon.ViewModel();
        private static List<ViewModelCommon.Items2> getAccountingRowsListEdited = new List<ViewModelCommon.Items2>();
        {
            DataContext = view;
            InitializeComponent();
        }

        private async Task GetAccountinTransactionsAsync()
        {
           await Task.Run(() =>
            {
                getAccountingRowsList = client.GetAccountingTransactions(ftglist[index], 0, ref status).ToList();

                foreach (var v in getAccountingRowsList)
                {
                        getAccountingRowsListEdited.Add(new ViewModelCommon.Items2
                        {
                            itemName2 = v.ver.ToString(),
                            value2 = v.text,
                            vertyp = v.vtyp,
                            s2 = v.kto.ToString(),
                            s3 = v.trdat.ToString()
                        });
                }
                Task.Run(async () =>
                {
                    await SearchAndDisplayResult();
                });
            });
        }

        private async Task SearchAndDisplayResult(int exclusion = 0)
        {
            await Task.Run(() =>
             {
                var verfikationer = getAccountingRowsListEdited.Where(u => u.vertyp != exclusion).Count(u => u.s2.ToString().Equals("0"));

                view.VerifikationerTotal = verfikationer.ToString();

             });
        }

视图模型:

class ViewModelCommon
    {
        public abstract class ViewModelBase : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;

            protected bool SetProperty<T>(ref T field, T newValue, [CallerMemberName]string propertyName = null)
            {
                if (!EqualityComparer<T>.Default.Equals(field, newValue))
                {
                    field = newValue;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                    return true;
                }
                return false;
            }

            protected virtual void OnPropertyChanged(string propertyName)
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
            }
            protected void Test(string sb)
            {
                Transaktioner tr = new Transaktioner("");
                tr.ExcludeStringChanged(sb);
            }
        }

public class ViewModel : ViewModelBase
        {
            private string _verifikationerTotal;
            public string VerifikationerTotal
            {
                get { return _verifikationerTotal; }
                set
                {
                    if (value != _verifikationerTotal)
                    {
                        _verifikationerTotal = value;
                        OnPropertyChanged("VerifikationerTotal");
                    }
                }
            }

            private string _ExcludeString;
            public string ExcludeString
            {
                get { return _ExcludeString; }
                set
                {
                    if (value != _ExcludeString)
                    {
                        _ExcludeString = value;
                        OnPropertyChanged("ExcludeString");
                        Test(ExcludeString);
                    }
                }
            }
        }

WPF:

<TextBox x:Name="TextBoxVerifikationerTotal" Text="{Binding VerifikationerTotal}" IsEnabled="False" HorizontalAlignment="Left" Height="23" Margin="583,182,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="99"/>

<TextBox HorizontalAlignment="Left" Height="23" Margin="837,10,0,0" TextWrapping="Wrap" Text="{Binding Path=ExcludeString, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" VerticalAlignment="Top" Width="286"/>

上面的代码按预期工作。

在 UI 中有一个选项可以引入可选属性来排除值。这些绑定到“ExludeString”,这也可以工作并触发事件再次将其传递给 SearchAndDisplayResult(int exclude = 0),并传递 int 的替换值。在调试时,我可以看到该事件可以成功找到一个新值并将其传递给 ViewModel,但它不会更新 UI。

对于为什么 UI 没有更新有什么想法吗?提前谢谢!

代码已缩短以显示生命体征

【问题讨论】:

  • 如果没有可靠地重现问题的良好minimal reproducible example,即使不是不可能,也很难回答问题。此类问题的一个常见原因是绑定中使用的视图模型与正在更新的视图模型的实例不同。您发布的代码似乎没有这个问题,但由于它不是minimal reproducible example,因此无法确定。奇怪的是,您的基本视图模型类中有 SetProperty() 方法,但似乎没有使用它。同样,这似乎不会导致您的问题,但没有足够的信息。
  • @PeterDuniho 感谢您抽出宝贵时间对我的问题发表评论。我现在才意识到我已经拿走了很多东西才能复制它。我确实找到了解决问题的方法。它与ViewModelCommon.ViewModel view = new ViewModelCommon.ViewModel(); 不是私有静态有关。我在另一个问题中读到了这篇文章,他们建议由于我正在处理异步任务,它可能会启动一个新实例,因此不会更新。

标签: c# wpf user-interface mvvm binding


【解决方案1】:

这个案例的答案是

ViewModelCommon.ViewModel view = new ViewModelCommon.ViewModel();

在使用任务时未设置为私有静态。

【讨论】:

  • 你解决了吗?我与同样的问题作斗争。我的 MVVM 实现和你的一样。第一次一切正常,第二次调用,NotifyPropertyChanged 什么都不做。它是从异步方法调用的(但任务正在运行并且值已更改)
猜你喜欢
  • 2021-12-20
  • 2014-11-23
  • 1970-01-01
  • 1970-01-01
  • 2016-12-17
  • 2022-11-11
  • 1970-01-01
  • 2012-08-17
相关资源
最近更新 更多