C# WPF/MVVM在我单击窗口之前不会更新

C# WPF/MVVM在我单击窗口之前不会更新,c#,wpf,mvvm,C#,Wpf,Mvvm,我有一个面板,上面有一个按钮,用来触发外部摄像头的图像捕获。捕获可能需要几秒钟,因此我希望在捕获过程中禁用该按钮。我还希望在我的程序运行控制脚本时能够防止用户捕获。以下是我的ViewModel类: public class CameraControlViewModel : ViewModelBase { public CameraControlViewModel() { } public CameraControlViewModel( DataModel da

我有一个面板,上面有一个按钮,用来触发外部摄像头的图像捕获。捕获可能需要几秒钟,因此我希望在捕获过程中禁用该按钮。我还希望在我的程序运行控制脚本时能够防止用户捕获。以下是我的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;
}
公共类CameraControlViewModel:ViewModelBase { 公共CameraControlViewModel() { } 公共摄像机控制器视图模型(数据模型数据模型) :基本(数据模型) { dataModel.PropertyChanged+=DataModelOnPropertyChanged; _captureImageCommand=新的RelayCommand(captureImage); _capturedImage=新的位图图像(); _capturedImage.BeginInit(); _capturedImage.UriSource=新Uri(“Images/fingerprint.jpg”,UriKind.Relative); _capturedImage.CacheOption=BitmapCacheOption.OnLoad; _capturedImage.EndInit(); } 公共ICommand captureMageCommand { 获取{return\u captureImageCommand;} } 公众形象 { 获取{return!dataModel.IsScriptRunning&!\u captureInProgress;} } 公共图书馆正在进行中 { 获取{return\u captureInProgress;} 设置 { if(_captureInProgress!=值) { _captureInProgress=值; 关于财产变更(“IsCaptureInProgress”); OnPropertyChanged(“CanCaptureImage”); } } } 公共整数百分比已完成 { 获取{return\u percentDone;} 设置 { 如果(_percentDone!=值) { _完成百分比=数值; OnPropertyChanged(“完成百分比”); } } } 公共位图图像捕获图像 { 获取{return\u capturedImage;} } 私有void DataModelOnPropertyChanged(对象发送方,PropertyChangedEventArgs PropertyChangedEventArgs) { 字符串属性=propertyChangedEventArgs.PropertyName; 如果(属性==“IsScriptRunning”) { OnPropertyChanged(“CanCaptureImage”); } 已更改的不动产(不动产); } 私有void captureImage(对象参数) { IsCaptureInProgress=true; 完成百分比=0; //TODO:删除此占位符。 新的伪造图像捕获(本); //待办事项(!) } 内部无效捕获完成() { IsCaptureInProgress=false; } //当我们可以拍摄图像时,请删除此占位符。 私有类FakeImageCapture { CameraControlViewModel\u viewModel; 整数计数; 定时器_Timer=新定时器(); 公共FakeImageCapture(CameraControlViewModel viewModel) { 这是。_viewModel=viewModel; _时间间隔=50; _timer.appeated+=TimerOnTick; _timer.Start(); } 私有void TimerOnTick(对象发送方,EventArgs EventArgs) { ++_计数;
如果(_count而不是使用单独的IsEnabled绑定来启用/禁用按钮,那么实际上应该只使用RelayCommand的CanExecute谓词:

这将确保在调用CommandManager.InvalidateRequestSuggested()时正确启用/禁用该按钮。删除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;
}

您确定脚本没有继续运行吗?当然,@ernodeweard。当您在CanCaptureImage获取程序上设置断点时,是否在捕获完成后对其进行评估?必须向UI发出信号,要求重新评估CanCaptureImage…也许您可以尝试在中引发CaptureImageCommand的ICommand.CanExecuteChanged事件更改值后,IsCaptureInProgress属性设置器将被禁用。@ErnodeWeerd是的,该属性的计算正确。但直到我单击其他位置后,按钮才刷新。我认为这可能与按钮样式有关,但我关闭了所有设置,默认的视觉效果仍会出现这种情况。我认为这是使事情正常工作的原因。我添加了canExecute谓词,并返回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;
}