1

如果 II 只是没有弄清楚实际的方法,我深表歉意,但我已经浏览了各种博客文章并且觉得离答案更近了。

我正在编写一个 WP7 应用程序,它本质上是一个将时间转换为成本的秒表。

该模型包含方法 Start() 和 Pause() 以及双重属性 Cost。在 ViewModel 中,我将 ICommands 用于 Start() 和 Pause(),这会触发底层模型函数。然而,在调用 Start() 之后,我希望 UI 能够反映成本的增加。

我考虑了几种方法:

  1. ViewModel 通过一个自我实现的订阅者模型订阅模型,并且模型在模型运行时每隔几毫秒通知所有订阅者。
  2. View Model StartCommand 启动一个后台工作程序,该工作程序每隔几毫秒在 Cost 属性上触发一个 RaisePropertyChanged 事件。

我选择了第二个建议,因为模型根本不需要线程(它只记录用户按下开始和暂停的时间,并在成本计算中使用它)。我的方法基于http://msdn.microsoft.com/en-us/library/cc221403(VS.95).aspx

但是,当我尝试运行它时,我得到一个“UnauthorizedAccessException”。代码如下:

Backgroundworker 在构造函数中被创建为 VM 成员

public MeetingCostViewModel()
{
    _backgroundWorker = new BackgroundWorker
    {
        WorkerSupportsCancellation = true,
        WorkerReportsProgress = false,
    };
    _backgroundWorker.DoWork += DoWork;
}

StartCommand 触发后台工作者运行

private DelegateCommand _startCommand;
    public ICommand StartCommand
    {
        get
        {
            return _startCommand ?? (_startCommand = new DelegateCommand(
                delegate
                {
                    _meetingCost.Start();
                    _keepUpdating = true;
                    if (_backgroundWorker.IsBusy != true)
                    {
                        _backgroundWorker.RunWorkerAsync();
                    }
                }));
        }
    }

这是基于http://blog.lab49.com/archives/1166的实际工作方法

private void DoWork(object sender, DoWorkEventArgs e)
{
    while (true)
    {
        PropertyChangedEventHandler temp = PropertyChanged;
        if (temp != null)
        {
            temp(this, new PropertyChangedEventArgs("Cost"));
        }
        Thread.Sleep(50);
    }
}

我不确定这是否是正确的方法,但我想保持 View 数据绑定并且没有“代码隐藏”,但是这里的大多数替代响应都需要明确设置控件,我想不惜一切代价避免。

4

2 回答 2

1

UnauthorizedAccessException 可能意味着您正在从不同的线程访问 UI 对象。您的事件处理程序在错误的线程上触发。

更改代码以使用将在 UI 线程上触发的 DispatcherTimer。

于 2012-04-06T22:02:21.767 回答
0

另一种解决方案是在 的报告进度事件处理程序中进行更新BackgroundWorker。它将自动编组到正确的线程。

于 2012-04-06T22:30:04.437 回答