0

外部カメラからの画像キャプチャをトリガーするために使用されるボタンが付いたパネルがあります。キャプチャには数秒かかることがあるため、キャプチャの進行中はボタンを無効にしたいと考えています。また、プログラムが制御スクリプトを実行しているときにユーザーがキャプチャするのを防ぐこともできます。ここに私の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>

「キャプチャ」ボタンをクリックするとうまくいきます。ボタンが無効になり、別の場所にプログレス バーが表示され、(現在偽造された) 画像キャプチャの進行状況が示されます。CanCaptureImageただし、メソッドでプロパティを設定しても、キャプチャが完了するcaptureComplete()と、ボタンは「有効」な外観に戻りません。これは、ウィンドウ内のどこか (どこでも) をクリックしたときにのみ実行されます。ただし、ボタンをもう一度クリックして 2 番目のキャプチャをトリガーできるため、実際にはボタンが有効になっています。

CommandManager.InvalidateRequerySuggested()私は内部で試しcaptureComplete()ましたが、それは役に立ちません。何か案は?

4

1 に答える 1

1

ボタンを有効/無効にするために別の IsEnabled バインディングを使用するのではなく、RelayCommand の CanExecute 述語を使用する必要があります

これにより、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;
}
于 2013-07-02T13:35:45.693 に答える