2013-04-10 118 views
2

我是WPF的新手。我想了解使用WPF綁定的MVVM模式。我有以下2類使用WPF數據綁定設計響應式UI

  1. MainWindow.xamal
  2. 視圖模型

    我有三個控制

    1. 文本框,顯示視圖模型
    2. 文本框,顯示「狀態的 '名稱' 屬性'ViewModel的依賴項屬性
    3. 調用'Execute'方法的按鈕'ViewModel'類。

    現在,Execute()方法有點龐大,所以我創建了一個委託並異步調用它。但是我的UI阻止其不更新「狀態」依賴屬性

請參閱下面的類值。

App.xaml.cs

namespace bindingDemo 
{ 
    /// <summary> 
    /// Interaction logic for App.xaml 
    /// </summary> 
    public partial class App : Application 
    { 
     protected override void OnStartup(StartupEventArgs e) 
     { 
      base.OnStartup(e); 
      MainWindow mw = new MainWindow(); 
      ViewModel vm = new ViewModel(); 

      ///Set data context property of main windows. 
      mw.DataContext = vm; 
      mw.Show(); 
     } 
    } 
} 

MainWindow.xaml

<Window x:Class="bindingDemo.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" Height="350" Width="525"> 
<Grid> 
    <TextBox Text="{Binding Name, Mode=TwoWay}" Height="23" HorizontalAlignment="Left" Margin="76,26,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" /> 
    <Button Command="{Binding Path=MyCommand}" Content="Button" Height="23" HorizontalAlignment="Left" Margin="76,127,0,0" Name="button1" VerticalAlignment="Top" Width="120" /> 
    <TextBox Text="{Binding Path=Status}" Height="23" HorizontalAlignment="Left" Margin="76,55,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" /> 
</Grid> 

ViewModel.cs

namespace bindingDemo 
{ 
    public class ViewModel : DependencyObject , ICommand 
    { 
     public string Status 
     { 
      get { return (string)GetValue(StatusProperty); } 
      set { SetValue(StatusProperty, value); } 
     } 

     // Using a DependencyProperty as the backing store for Status. This enables animation, styling, binding, etc... 
     public static readonly DependencyProperty StatusProperty = 
      DependencyProperty.Register("Status", typeof(string), typeof(ViewModel), new UIPropertyMetadata("In Progress..."));  

     private ICommand _command = null; 

     public ViewModel() 
     { 
      Name = "Default Name"; 
     } 


     public void Execute(object parameter) 
     {    
      Action a = new Action(() => 
      { 
       ///While this code is being executed, UI gets blocked. 
       Console.WriteLine(Name); 
       Name = "OK"; 
       Status = "Connecting to database...."; 
       Thread.Sleep(2000); 
       Status = "Connected to database...."; 
       Thread.Sleep(2000); 
       Status = "Performing validations...."; 
       Thread.Sleep(2000); 
       Status = "Data saved."; 

      }); 

      /// Even if I have invoked operation asynchronously, UI is not getting updated 
      /// UI is freezing for 6 seconds and can directly see last 'Status' message on UI 
      Dispatcher.BeginInvoke(a, null);    
     } 

     public string Name { get; set; } 

     public ICommand MyCommand 
     { 
      get 
      { 
       return this; 
      } 
     } 

     public bool CanExecute(object parameter) 
     { 
      return true; 
     } 

     public event EventHandler CanExecuteChanged; 
    } 
} 

有人可以幫我在這?

問候, 與Hemant

+0

第一件事來記住:NotifyPropertyChanged,看看這個,告訴UI背景中的東西已經改變了。 – Terry 2013-04-10 06:47:13

+0

@djerry根據我的理解,DependencyProperty還能夠通知UI後臺中的某些內容已更改。事實上,我可以看到最後的狀態,即'數據保存'。在UI上,但因爲它似乎是一個UI線程的阻塞調用它不更新/反映其他狀態消息。糾正我,如果我錯了... – user2243747 2013-04-10 06:50:36

+0

請確保您的'PropertyChanged'通知在UI線程上運行。嘗試在UI線程上分配狀態。 – 2013-04-10 06:55:47

回答

2

很少有東西在這裏:

  1. DependencyProperty是......嗯,類與依賴屬性。對於查看模型,請執行INotifyPropertyChangedDependencyObject現在將您的繼承關係在一起,而這不是它的預期用法。

  2. 您正在調用Dispatcher的操作,Dispatcher應該用於在調度程序線程上運行函數,在這種情況下,它將是UI線程。難怪它會被阻塞,你正在調用一個UI線程的方法。 Dispatcher在您希望從後臺任務更改UI綁定值(例如報告某種進度)時非常有用。你必須分開你的邏輯,在後臺進行處理,然後報告結果。

所以,他這樣說,你Execute或許應該是這樣的(使用C#5):

private async Task DoStuff() 
{ 
    await Task.Delay(5000); 
    //or drop the async modifier and 'return Task.Delay(5000);' 
} 

public async void Execute(object parameter) 
{ 
    await DoStuff(); 
    //Add some checks if it really was 'OK', catch exceptions etc 
    Name = "OK"; 
} 

用C#4(未經測試):

private Task DoStuff() 
{ 
    return Task.Factory.StartNew(() => Thread.Sleep(5000)); 
} 

public void Execute(object parameter) 
{ 
    DoStuff().ContinueWith(result => Name = "OK", TaskScheduler.FromCurrentSynchronizationContext()); 
    //Same as above, probably should specify appropriate TaskOptions to run the continuation 
    //only when the task was completed successfully. 
} 
4

甲視圖模型通常不包含的依賴特性。爲了能夠通過數據綁定更新UI,它必須實現INotifyPropertyChanged接口。
嘗試實現您的視圖模型是這樣的:

public class ViewModel : INotifyPropertyChanged 
{ 
    private string _status; 

    public string Status 
    { 
     get { return _status; } 
     set 
     { 
      if(_status == value) 
       return; 
      _status = value; 

      OnPropertyChanged("Status"); 
     } 
    } 

    public event EventHandler<PropertyChangedEventArgs> PropertyChanged; 

    private void OnPropertyChanged(string propertyName) 
    { 
     var handler = PropertyChanged; 
     if(handler != null) 
      handler(new PropertyChangedEventArgs(propertyName)); 
    } 

    // ... 
} 

實現您的視圖模型ICommand看起來相當奇怪了。