【问题标题】:WPF / MVVM not updating till I click in the window在我单击窗口之前,WPF / MVVM 不会更新
【发布时间】:2013-06-29 16:11:45
【问题描述】:

我有一个面板,上面有一个按钮,用于触发来自外部摄像头的图像捕获。捕获可能需要几秒钟,因此我希望在捕获过程中禁用该按钮。我还希望能够在我的程序运行控制脚本时阻止用户捕获。这是我的 ViewModel 类:

public class CameraControlViewModel : ViewModelBase
{
    public CameraControlViewModel()
    {

    }

    public CameraControlViewModel( DataModel dataModel )
    : base( dataModel )
    {
        dataModel.PropertyChanged += DataModelOnPropertyChanged;    

        _captureImageCommand = new RelayCommand( captureImage );
        _capturedImage = new BitmapImage();
        _capturedImage.BeginInit();
        _capturedImage.UriSource = new Uri( "Images/fingerprint.jpg", UriKind.Relative );
        _capturedImage.CacheOption = BitmapCacheOption.OnLoad;
        _capturedImage.EndInit();
    }

    public ICommand CaptureImageCommand
    {
        get { return _captureImageCommand; }
    }

    public bool CanCaptureImage
    {
        get { return !dataModel.IsScriptRunning && !_captureInProgress; }
    }

    public bool IsCaptureInProgress
    {
        get { return _captureInProgress; }
        set
        {
            if (_captureInProgress != value)
            {
                _captureInProgress = value;
                OnPropertyChanged( "IsCaptureInProgress" );
                OnPropertyChanged( "CanCaptureImage" );
            }
        }
    }

    public int PercentDone
    {
        get { return _percentDone; }
        set
        {
            if (_percentDone != value)
            {
                _percentDone = value;
                OnPropertyChanged( "PercentDone" );
            }
        }
    }

    public BitmapImage CapturedImage
    {
        get { return _capturedImage; }    
    }

    private void DataModelOnPropertyChanged( object sender, PropertyChangedEventArgs propertyChangedEventArgs )
    {
        string property = propertyChangedEventArgs.PropertyName;
        if (property == "IsScriptRunning")
        {
            OnPropertyChanged( "CanCaptureImage" );    
        }

        OnPropertyChanged( property );
    }

    private void captureImage( object arg )
    {
        IsCaptureInProgress = true;
        PercentDone = 0;

        // TODO: remove this placeholder.
        new FakeImageCapture( this );

        // TODO (!)    
    }

    internal void captureComplete()
    {
        IsCaptureInProgress = false;
    }

    // Remove this placeholder when we can take images.
    private class FakeImageCapture
    {
        CameraControlViewModel _viewModel;
        int _count;
        Timer _timer = new Timer();

        public FakeImageCapture( CameraControlViewModel viewModel )
        {
            this._viewModel = viewModel;

            _timer.Interval = 50;
            _timer.Elapsed += TimerOnTick;
            _timer.Start();
        }

        private void TimerOnTick( object sender, EventArgs eventArgs )
        {
            ++_count;
            if (_count <= 100)
            {
                _viewModel.PercentDone = _count;
            }
            else
            {
                Application.Current.Dispatcher.Invoke( (Action)_viewModel.captureComplete );
                _timer.Stop();
                _timer = null;
                _viewModel = null;
            }
        }
    }

    private readonly ICommand _captureImageCommand;
    private volatile bool _captureInProgress;
    private BitmapImage _capturedImage;
    private int _percentDone;
}

这是按钮的 XAML:

<Button Command="{Binding CaptureImageCommand}" 
        Grid.Row="0" Grid.Column="0" 
        Margin="4" 
        IsEnabled="{Binding CanCaptureImage}"
        ToolTip="Capture Image">
            <Image Source="../Images/camera-icon.gif" Width="64" Height="64" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Button>

单击“捕获”按钮即可。该按钮禁用,并在其他地方出现一个进度条,显示(当前伪造的)图像捕获进度。但是,当捕获完成时,即使我在 captureComplete() 方法中设置了 CanCaptureImage 属性,按钮也不会变回其“启用”外观。只有当我单击窗口中的某个地方(任何地方)时,它才会这样做。但是,该按钮实际上已启用,因为我可以再次单击它来触发第二次捕获。

我在captureComplete() 中尝试过CommandManager.InvalidateRequerySuggested(),但这并没有帮助。有什么想法吗?

【问题讨论】:

  • 你确定脚本没有还在运行吗?
  • 当然,@ErnodeWeerd。
  • 当您在 CanCaptureImage getter 上设置断点时,是否在捕获完成后对其进行评估?必须向 UI 发出信号,表明应该重新评估 CanCaptureImage...
  • 也许您可以在更改值后尝试在 IsCaptureInProgress 属性设置器中引发 CaptureImageCommand 的 ICommand.CanExecuteChanged 事件。
  • @ErnodeWeerd 是的,该属性正在正确评估。但是在我单击其他地方之前,按钮仍然不会刷新。我认为这可能与我的按钮样式有关,但我将其全部关闭,默认视觉效果仍然会发生这种情况。

标签: c# wpf mvvm


【解决方案1】:

与其使用单独的 IsEnabled 绑定来启用/禁用按钮,不如只使用 RelayCommand 的 CanExecute 谓词:http://msdn.microsoft.com/en-us/library/hh727783.aspx

这将确保在调用 CommandManager.InvalidateRequerySuggested() 时正确启用/禁用按钮。去掉 CanCaptureImage 属性,修改你的代码如下:

public CameraControlViewModel( DataModel dataModel )
: base( dataModel )
{
    dataModel.PropertyChanged += DataModelOnPropertyChanged;    

    _captureImageCommand = new RelayCommand( captureImage, captureImage_CanExecute );
    _capturedImage = new BitmapImage();
    _capturedImage.BeginInit();
    _capturedImage.UriSource = new Uri( "Images/fingerprint.jpg", UriKind.Relative );
    _capturedImage.CacheOption = BitmapCacheOption.OnLoad;
    _capturedImage.EndInit();
}

private bool captureImage_CanExecute( object arg)
{
    return !dataModel.IsScriptRunning && !_captureInProgress;
}

【讨论】:

  • 我认为这就是让事情顺利进行的原因。我没有完全按照您所做的那样做,而是添加了 canExecute 谓词,并使其返回 CanCaptureImage。六,半打。谢谢!
猜你喜欢
  • 2013-09-09
  • 1970-01-01
  • 2011-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-08
  • 2015-03-03
  • 1970-01-01
相关资源
最近更新 更多