2013-11-04 2 views
1

좋아, 설명하겠습니다.MVVM에서 UI를 강제로 업데이트 할 수 있습니까?

나는 스캔 프로세스의 일종을 트리거 할 수있는 어플리케이션이있다. 이 스캔 프로세스는 무언가를하는 10 명의 백그라운드 작업자를 시작합니다 (숫자 만). 오초 (다시, 단지 수) 후 내가 좋아하는 것에

  • 죽여 모든 배경 노동자
  • 내가 그들을
  • 을 모두로부터 얻은 데이터에 몇 가지 계산을 수행 (나는 그것을 위해 CancelAsync를 사용하고 있습니다)
  • 데이터가 표시되도록 UI를 업데이트하고 일부 버튼을 사용 (이 버튼은 ViewModel 명령을 통해 바인딩 PerformUpdateCommand라고 그들은 IsPerformUpdateAllowedCanExecute 속성이 있습니다. 내 작업을 완료 할 때 IsPerformUpdateAllowed 종속성 속성이 설정됩니다.
나는 내가 할 것이라고 생각 무엇

:

  • 를 배경 노동자를 유발 한 후에는 5 초 간격으로 배차 타이머를 시작합니다.
  • DispatcherTimer이 "틱"되면 데이터를 계산하고 IsPerformUpdateAllowed 속성을 true 또는 false로 설정합니다.

기본적으로 예상대로 작동합니다 (UI는 반응이 좋으며, ...). 작은 사소한 문제 만 제외하면 UI가 업데이트되지 않습니다 (버튼이 활성화되지 않음). 창을 배경으로두고 전경으로 되돌리면 명령이 활성화되고 IsPerformUpdateAllowed 속성도 true로 설정됩니다. 또한 버튼을 누른 후 비활성화 된 상태에서 버튼을 누르면 활성화됩니다.

그래서 종속성 속성을 올바르게 설정했지만 UI가이 변경에 반응하지 않습니다.

아무도 알아? 흥미롭게도 UI의 일부 텍스트를 레이블로 설정합니다.이 텍스트는 올바르게 업데이트됩니다. CanExecute 명령을 알려주는 속성이 UI 업데이트를 트리거하지 않는다는 것입니다.

타이머를 초기화하는 코드입니다. 여기

  <Label Grid.Row="1" Grid.Column="1"> 
       <Hyperlink Command="{Binding ReadSettingsCommand}"> 
        <TextBlock Text="{Binding Source={StaticResource Loc}, Path=Labels.ReadSettings}"></TextBlock> 
       </Hyperlink> 
      </Label> 

이 코드는

public RelayCommand ReadSettingsCommand 
    { 
     get 
     { 
      return _readSettingsCommand 
       ?? (_readSettingsCommand = new RelayCommand(ExecuteReadSettings,() => IsScannedDeviceAvailable && !IsUpdateInProgress)); 
     } 
    } 

명령 코드입니다 : 명령은 WPF 요소에 바인딩하는 방법을

 _scanTimer = new DispatcherTimer(); 
     _scanTimer.Interval = new TimeSpan(0, 0, 0, 3); 
     _scanTimer.Tick += delegate 
     { 
      // After the timer has elapsed (some time passed), cancel all scans and update the result 
      _scanTimer.Stop(); 
      UpdateScanResults(); 
      CancelNormalScans(false); 
     }; 
     _scanTimer.Start(); 

코드 (버튼은 하이퍼 링크 실제로) 실제로 두 종속성 속성에 종속 IsScannedDeviceAvailable 및 IsUpdateInProgress 아닙니다. 둘 다 종속성 속성입니다.

업데이트 : 방금 CanExecute 속성에 대한 바인딩이 한 번만 읽음을 읽었습니다. 그것을 다시 유효화하려면 명령에서 RaiseCanExecuteChanged를 호출해야합니다. 이 방법이 효과적이지만, 두 속성 중 하나가 변경 될 때마다 수동으로 호출해야하기 때문에 다소 번거롭습니다. 실제로 저는 그것이 자동으로 처리되기를 원했습니다. 이것이 어떻게 더 쉽게 이루어질 수 있는지에 대한 아이디어가 있습니까? CanExecute와 속성 사이에 단방향 바인딩을 사용하는 방법이 있습니까?

+0

IsPerformUpdateAllowed DependencyProperty는 무엇입니까? – markmnl

+0

ICommands가 CanExercuteChanged 이벤트를 발생시키지 않습니다. – Aron

+0

@Aron : RaiseCanExecuteChanged를 수동으로 호출하는 것보다 더 좋은 방법이 있습니까? –

답변

3

IsScannedDeviceAvailable/IsUpdateInProgress가 설정 될 때마다 RaiseCanExecuteChanged 중 하나를 사용하십시오. 또는 내 개인적인 선호는 자신의 구현을 만들 수 ICommand 꽤 간단하기 때문에 어쨌든. 당신이 재산을 기반으로 Command.CanExecute()의 변화를 유발하는 경우

public class FooCommand : ICommand 
{ 
    private bool _canExecute; 
    private Action _delegate; 
    public event EventHandler CanExecuteChanged; 
    public new bool CanExecute 
    { 
     get 
     { 
      return _canExecute; 
     } 
     set 
     { 
      _canExecute = value; 
      if(CanExecuteChanged != null) 
       CanExecuteChanged(); 
     } 
    } 

    public void Execute(object parameter) 
    { 
     _delegate(); 
    } 

    bool ICommand.CanExecute() 
    { 
     return CanExecute; 
    } 

    public FooCommand(Action action) 
    { 
     _delegate = action; 
    } 
} 
+0

고마워, 그게 효과가있다. 그러나, 나는 실제로 모든 것을 다른 방향으로 코드화하고 싶었습니다. 명령에 대한 모든 조건이 충족되면 자동으로 활성화됩니다. –

0

, 당신은 또한 재평가 할 CanExecute()을 강제로 CommandManager.InvalidateRequerySuggested()를 호출 할 수 있습니다.

+0

모든 명령을 평가해야하므로 매우 효율적이지는 않습니다. –

관련 문제