Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf 状态栏不总是更新_Wpf_Multithreading_Mvvm_C# 4.0 - Fatal编程技术网

Wpf 状态栏不总是更新

Wpf 状态栏不总是更新,wpf,multithreading,mvvm,c#-4.0,Wpf,Multithreading,Mvvm,C# 4.0,我对MVVM比较陌生,我正在尝试为MVVM WPF应用程序编写一个基本状态栏。我想我已经掌握了要点,但出于某种原因,状态栏并不总是更新,我也不知道为什么 在我的ViewModel中,我有一个基本属性,在更改状态消息时更新该属性: public string StatusMessage { get { return _statusMessage; } set { if (value == _statusMessage) return; _st

我对MVVM比较陌生,我正在尝试为MVVM WPF应用程序编写一个基本状态栏。我想我已经掌握了要点,但出于某种原因,状态栏并不总是更新,我也不知道为什么

在我的ViewModel中,我有一个基本属性,在更改状态消息时更新该属性:

public string StatusMessage
{
    get { return _statusMessage; }
    set
    {
        if (value == _statusMessage) return;
        _statusMessage = value;
        base.OnPropertyChanged(() => this.StatusMessage);
    }
}
我的OnPropertyChanged方法(我在一个实现INotifyPropertyChanged的基础ViewModel类中拥有)看起来是这样的(从Gunther Foidl中得到了这个想法;我希望我能为它赢得荣誉,因为我认为它很光滑,但我不是很聪明):

受保护的虚拟void OnPropertyChanged(表达式exp)
{
MemberExpression me=将主体作为MemberExpression进行扩展;
字符串propName=me.Member.Name;
PropertyChangedEventHandler处理程序=this.PropertyChanged;
if(处理程序!=null)
{
处理程序(此,新PropertyChangedEventArgs(propName));
}
}
无论如何,除了一个控件外,这对我的所有控件都非常有效。在MainWindow.xaml文件中,我有一个绑定到上述属性的StatusBarItem控件,如下所示(由于空间原因,xaml的其余部分已被修剪):


当我运行我的应用程序时(除了从模板生成一个文档和一堆其他资源相当密集的东西之外,还需要点击几个数据库),状态栏上会显示一些但不是全部的消息。我已经调试并验证了所有消息都进入了上面的StatusMessage属性(以及随后的私有变量),它们在UI中似乎没有刷新

我已经看过几个将BackgroundWorker实例用于ProgressBar控件的示例,但没有看到任何StatusBarItem控件的示例,并且不确定如何将一个实例转换为另一个实例

我在以前的C#4.0和WPF应用程序中也使用过任务,我认为这可能是一个很好的方法,但我还没有真正弄清楚如何/在何处指定UI任务(我以前一直在主窗口的代码隐藏中使用它,但我正在努力实现零代码隐藏以保持MVVM)

我非常确信多线程方法是一条可行的道路;我只是对一种方法知之甚少(我知道这一点和那一点),无法让它发挥作用。我确实看到一些帖子直接使用了旧的线程方法,但在我开始使用.NET4.0中的任务之前,我基本上没有使用多线程编程(发现它们更容易理解和跟踪),因此我在理解它们时遇到了一些困难


有谁能同情我,给我指出正确的方向,或者建议我做进一步的调试吗?谢谢

通知无法通过的地方

我会尝试:

  • 在textbinding上添加一个虚拟valueconverter,这样您就可以设置断点并查看是否调用了您
  • 调度属性集以在“更好”的时间设置值-这有时是必要的
调度集合可能会达到这个目的。

1)基于反射的绑定有时会因为内联而成为错误源。尝试查看如果使用简单字符串而不是反射更改notifypropertychanged会发生什么

2) 如果您使用的是多线程,则可能会设置StatusMessage而不是来自UIThread。在这种情况下,它将无法更新UI,您可以调用UI Dispatcher上的setter代码以查看这是否有帮助

3) 检查绑定是否工作,在xaml表单的构造函数中,直接在VM上修改StatusMessage,并查看更改是否显示在UI上,而不调用多线程服务调用,这些调用会为简单的textblock-string绑定引入额外的变量

4) 如果这对您没有帮助,您可以创建一个简单的xaml表单,使用单个文本块将其绑定到您的大viewmodel并查看会发生什么,如果没有任何效果,您可以开始切割VM类以使其更简单,这样绑定最终开始工作,并且您会发现一个错误


5) 如果您认为statusbar是问题所在,请查看没有statusbar的单个textblock(从您的示例中提取xaml部分)是否有效

我遇到了类似的更新textblock问题,您最终找到了解决方案吗?我能够使任务代码正常工作,通过将UI TaskScheduler传递到我的ViewModel中,并对所述调度器生成的任务进行更新。如果时间允许,我会在一个单独的答案中发布代码示例。@Julien,以下是我所做的。在App.xaml.cs文件中初始化ViewModel时,我传入了两个TaskFactory实例:一个用于UI:
new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext())
,我称之为
UiTasks
,另一个用于其他所有
Task.Factory
,我称之为
DefaultTasks
。然后,我确保我的繁重工作在默认任务工厂下运行,并使用UI工厂更新我的属性:
this.UiTasks.StartNew(()=>this.StatusMessage=myMessage;})这似乎起到了作用。如果你愿意,我很乐意给你发一个更详细的例子。祝你好运谢谢你的解释,我会尽快试一试。如果我做不到,我会给你打电话;-)我设法让它工作使用一个味觉工厂!谢谢你的帮助;-)谢谢,瓦伦丁。事实证明,问题在于状态消息没有从UI线程更新(当时我不知道如何使用MVVM进行更新)。一旦我能够在我的App_启动例程中设置UI TaskScheduler/TaskFactory并将其传递到我的ViewModel的构造函数中,然后使用它生成一个任务来更新状态,它就发挥了巨大的作用。谢谢我不明白为什么起源线是个问题。WPF旨在自动将绑定通知封送到UI线程上,不是吗?
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> exp)
    {
    MemberExpression me = exp.Body as MemberExpression;
    string propName = me.Member.Name;

    PropertyChangedEventHandler handler = this.PropertyChanged;
    if (handler != null)
    {
        handler(this, new PropertyChangedEventArgs(propName));
    }
}
<StatusBarItem Grid.Column="0">
    <TextBlock TextTrimming="CharacterEllipsis" Text="{Binding Path=StatusMessage}" />
</StatusBarItem>