WPF / MVVM在我点击窗口之前不会更新。

9 浏览
0 Comments

WPF / MVVM在我点击窗口之前不会更新。

我有一个面板上有一个按钮,用于触发外部相机的图像捕捉。捕捉可能需要几秒钟时间,所以我希望在捕捉过程中禁用按钮。我还希望能够在我的程序运行控制脚本时阻止用户捕捉。这是我的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代码:


点击"捕捉"按钮没有问题。按钮被禁用,并且其他地方显示一个进度条,显示(当前模拟的)图像捕捉进度。然而,当捕捉完成后,即使我在`captureComplete()`方法中设置了`CanCaptureImage`属性,按钮仍然不会恢复到“启用”状态。只有当我在窗口中的任何地方单击时,它才会这样做。然而,按钮实际上是启用的,因为我可以再次点击它来触发第二次捕捉。

我尝试在`captureComplete()`方法中使用`CommandManager.InvalidateRequerySuggested()`,但没有效果。有什么想法吗?

0
0 Comments

问题的原因是没有正确使用CanExecute属性来启用/禁用按钮。解决方法是使用RelayCommand的CanExecute谓词,并在调用CommandManager.InvalidateRequerySuggested()时确保按钮正确启用/禁用。具体的修改代码如下:

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的值,可以解决问题。这样做与之前的方法效果一样。谢谢!

0