2011-10-19 41 views
0

我有一個WPF應用程序,我使用的是MVVM。等待光標在WPF PropertyChanged和綁定之間

在我看來,我的模型有:

private string logs; 
    public string Logs 
    { 
     get { return logs; } 
     set 
     { 
      logs = value; 
      OnPropertyChanged("Logs"); 
     } 
    } 

    private void ExecLoadData() 
    { 
     using (new WaitCursor()) 
      Logs = LogFile.ReturnContent(); 
    } 

    private RelayCommand loadData; 
    public ICommand LoadData 
    { 
     get 
     { 
      if (loadData == null) 
       loadData = new RelayCommand(param => this.ExecLoadData()); 
      return loadData; 
     } 
    } 

在View:

<i:Interaction.Triggers> 
    <i:EventTrigger EventName="Loaded"> 
     <i:InvokeCommandAction Command="{Binding LoadData}" /> 
    </i:EventTrigger> 
</i:Interaction.Triggers> 

我注意到的是,OnPropertyChanged的頁面上的拍攝和呈現數據之間出現延遲。

我需要一種方法來顯示等待光標到要顯示在屏幕上的數據。

已經實現了WaitCursor()方法,但等待光標纔會出現,直到數據文件加載到內存中,也就是加載數據到內存中,直到數據顯示在頁面上,光標保持正常。

任何提示?

編輯(與AngelWPF的幫助,最終的解決方案):)

private Boolean isBusy = false; 
    public Boolean IsBusy 
    { 
     get { return isBusy; } 
     set 
     { 
      if (isBusy == value) 
       return; 
      isBusy = value; 
      OnPropertyChanged("IsBusy"); 
     } 
    } 

    private string logs; 
    public string Logs 
    { 
     get { return logs; } 
     set 
     { 
      logs = value; 
      OnPropertyChanged("Logs"); 
     } 
    } 

    public void ExecuteBusy(DoWorkEventHandler doWorkEventHandler) 
    { 
     IsBusy = true; 

     var backgroundWorker = new BackgroundWorker(); 
     backgroundWorker.DoWork += doWorkEventHandler; 
     backgroundWorker.RunWorkerCompleted += (sender, e) => { IsBusy = false; }; 
     backgroundWorker.RunWorkerAsync(); 
    } 

    protected override void ExecLoadData() 
    { 
     LoadLogs(); 
    } 

    private void LoadLogs() 
    { 
     ExecuteBusy((sender, e) => 
     { 
      Logs = LogFile.ReturnContent(); 
     }); 
    } 

<Page.Resources> 
    <ut:BooleanVisibilityConverter x:Key="BooleanVisibilityConverter" /> 
</Page.Resources> 

<Page.DataContext> 
    <vm:ManutencaoMonitoracaoLogsViewModel/> 
</Page.DataContext> 

<i:Interaction.Triggers> 
    <i:EventTrigger EventName="Loaded"> 
     <i:InvokeCommandAction Command="{Binding LoadData}" /> 
    </i:EventTrigger> 
</i:Interaction.Triggers> 

<Grid> 

    <TextBox Text="{Binding Logs, Mode=OneWay}" VerticalScrollBarVisibility="Auto" IsReadOnly="True" BorderBrush="White" /> 

    <Border BorderBrush="Black" BorderThickness="1" Background="#80DBDBDB" Grid.RowSpan="3" 
      Visibility="{Binding IsBusy, Converter={StaticResource BooleanVisibilityConverter}}"> 
     <Grid> 
      <ct:LoadingAnimation HorizontalAlignment="Center" VerticalAlignment="Center"/>    
     </Grid> 
    </Border> 

</Grid> 

回答

0

你不應該有一個模型來實現光標的任何引用,你怎麼從UI的ExecelLoadData(調用方法?我建議在撥打電話前更改光標狀態,並在返回時更換

+0

嗨麥克!我編輯帖子e放更多的代碼。所以,我只需要知道如何在視圖中獲取「綁定後」事件。 – Alexandre

0

這需要通過我們稱之爲AsyncWorker的任何重要功能來編排任何重要功能。這是使用後臺工作者執行的異步命令。它具有從視圖模型啓動的一次觸發標誌爲true,以便在任何重要功能委託給窗口的裝飾器時運行它。當功能執行時,動畫指示用戶可能延遲的功能正在運行並且他/她應該等待。然後,當委託完成時,AsyncWorker自己隱藏動畫並將頁面正確顯示回給用戶。

http://elegantcode.com/2009/08/21/a-simple-wpf-loading-animation/

我可以想象這是可以做到這樣......

Characteristics of `AsyncWorker` 
    1. It is a Control that runs an animation such as 
     a neverending progressing progress bar 
     or rotating circles etc. in the adorner of the UI. 
    2. It accepts the parent panel on which the waiter animation is shown. 
    3. It has a boolean dependency property say "StartOperation".   
     When this changes to true we start the animation. 
     When true this also begins excuting the `WorkerDelegateCommand` given below. 
    4. It also has a ICommand dependency property called "WorkerDelegateCommand" 
     This will be supplied from your `ViewModel`. 
     It will hold the time consuming operation as a delegate. 

所以基本上,當我們設置AsyncWorker.StartOperation爲真,我們渲染父面板的裝飾器與動畫故事板和啓動後臺工作人員。這個後臺工作者在另一個線程上運行WorkerDelegateCommand。因此,您的緩慢操作在UI之外的另一個線程上運行。同時異步工作者動畫繼續運行。當WorkerDelegateCommand委託人完成其緩慢工作時,後臺工作人員DoWork調用退出並調用RunCompleted。在此我們將StartOperation設置爲false。

我們可以配置此AsyncWorker的方式是這樣...

<Grid> 
     <Button Content="Do some slow work" 
       Command="{Binding RunAsyncWorkerCommand}" /> 
     <AsyncWorker 
       ParentPanel="{Binding RelativeSource={RelativeSource 
             AncestorType={x:Type Grid}}}" 
       StartOperation="{Binding StartSlowWork, Mode=TowWay}" 
       WorkerDelegateCommand="{Binding MySlowDelegateCommand}" 
       Visibility="Collapsed" /> 
    </Grid> 

所以在上面的例子中,當布頓點擊網格,包含該按鈕,顯示服務員動畫,並開始執行操作緩慢。爲此,您的DataContext和/或ViewModel需要三個屬性...

1. `StartSlowWork` - A boolean flag to start AsyncWorker which is TwoWay bound. 
2. `RunAsyncWorkerCommand` - Command to set the `StartSlowWork` flag to true. 
3. `MySlowDelegateCommand` - Command to execute slow work. 

一旦你有了這個地方,每一個緩慢執行的操作都可以移動到AsyncWorker。

+0

嗨天使,很好的例子,謝謝!所以,我不知道如何處理這個屏幕渲染的開始和結束,你有一個例子嗎?即數據綁定的開始和結束事件? – Alexandre

+0

請看我的編輯。這對您的簡單要求來說可能看起來太多了,但這就是我一直在做的事情。沒有抱怨遠! :-) –

+0

嗨天使,我明白你的觀點,但我有一個問題:假設重大活動已經完成,並且這項活動的結果是1000件物品的清單。 所以,正如我所說的,在WPF中,視圖模型中的屬性分配與屏幕上的屬性顯示值之間通過數據綁定存在延遲。我相信,即使在這種實現方式下,延遲也會繼續存在,因爲它是數據綁定將屬性值轉換爲可視元素所需的時間。 – Alexandre