2013-02-14 33 views
0

我正在編寫一個WPF應用程序,並嘗試自學MVVM模式。我正在使用位於塞繆爾傑克的網站上的說明: http://blog.functionalfun.net/2008/09/hooking-up-commands-to-events-in-wpf.html如何在WPF應用程序中使用MVVM在ViewModel類和ICommand類之間共享數據?

我已經將我的命令綁定到按鈕,並將所有的東西都連接起來。命令類是ViewModel類的內部類,它們實現了ICommand。複雜的部分是從我的按鈕運行的命令需要訪問我的視圖上的數據。由於C#內部類無法訪問外部類的成員,因此我發現自己必須在ViewModel calss中聲明公共靜態變量,才能將數據傳遞給內部類。這似乎是一個ha and不馴的解決方案。有沒有人有更好的方法來做到這一點?

我的視圖模型代碼:

public class ApplicationViewModel 
{ 
    public ObservableCollection<App> AppCollection { get; set; } 
    static string searchString; 
    static string emailString; 
    public App SelectedApp { get; set; } 
    public string AppToSearch 
    { 
     get 
     { 
      return searchString; 
     } 
     set 
     { 
      searchString = value; 
     } 
    } 
    public string AppToRequest 
    { 
     get 
     { 
      get emailString; 
     } 
     set 
     { 
      // set static email String here 
     } 
    } 
    private SearchButtonCommand searchButtonCmd; 
    private ClearButtonCommand clearButtonCmd; 
    private EmailButtonCommand emailButtonCmd; 

    public ApplicationViewModel() 
    { 
     this.AppCollection = ApplicationsModel.Current; 
    } 

    public ICommand SearchButtonPressed 
    { 
     get 
     { 
      if (this.searchButtonCmd == null) 
      { 
       this.searchButtonCmd = new SearchButtonCommand(); 
      } 
      return this.searchButtonCmd; 
     } 
    } 

    public ICommand ClearButtonPressed 
    { 
     get 
     { 
      if (this.clearButtonCmd == null) 
      { 
       this.clearButtonCmd = new ClearButtonCommand(); 
      } 
      return this.clearButtonCmd; 
     } 
    } 

    public ICommand EmailButtonPressed 
    { 
     get 
     { 
      if (this.emailButtonCmd == null) 
      { 
       this.emailButtonCmd = new EmailButtonCommand(); 
      } 
      return this.emailButtonCmd; 
     } 
    } 

    private class SearchButtonCommand : ICommand 
    { 
     public event EventHandler CanExecuteChanged; 

     public void Execute(object parameter) 
     { 
      string searchkey = ApplicationViewModel.searchString; 
      ApplicationsModel.Current.Search(searchkey); 
     } 

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

    private class ClearButtonCommand : ICommand 
    { 
     public event EventHandler CanExecuteChanged; 

     public void Execute(object parameter) 
     { 
      ApplicationsModel.Current.ClearSearch(); 
     } 

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

    private class EmailButtonCommand : ICommand 
    { 
     public event EventHandler CanExecuteChanged; 

     public void Execute(object parameter) 
     { 
      string targetEmail = ApplicationViewModel.emailString; 
     } 

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

我的XAML:

<Window.DataContext> 
    <vm:ApplicationViewModel /> 
</Window.DataContext> 

<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto" /> 
     <RowDefinition Height="Auto" /> 
     <RowDefinition Height="*" /> 
     <RowDefinition Height="Auto" /> 
    </Grid.RowDefinitions> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="*" /> 
    </Grid.ColumnDefinitions> 
    <Image Grid.Row="0" Height="84" HorizontalAlignment="Left" Margin="0,5,5,5" Name="imgLogo" Stretch="Fill" VerticalAlignment="Top" Width="600" Source="C:\Images\bannerlong.png" /> 
    <Grid Grid.Row="1" HorizontalAlignment="Center" Margin="0,5,5,5" VerticalAlignment="Center"> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto" /> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="Auto" /> 
      <ColumnDefinition Width="Auto" /> 
      <ColumnDefinition Width="Auto" /> 
      <ColumnDefinition Width="Auto" /> 
     </Grid.ColumnDefinitions> 
     <Label Grid.Row="0" Grid.Column="0" Content="Search for Application"> 
      <Label.Foreground> 
       <SolidColorBrush Color="LightCyan" /> 
      </Label.Foreground> 
     </Label> 
     <TextBox Grid.Row="0" Grid.Column="1" Margin="3" Width="500" Text="{Binding AppToSearch}" /> 
     <Button Grid.Row="0" Grid.Column="2" HorizontalAlignment="Right" Width="100" Height="20" Margin="3" Background="LightCyan" Content="Search" vm:ButtonBehaviour.SearchCommand="{Binding SearchButtonPressed}" /> 
     <Button Grid.Row="0" Grid.Column="3" HorizontalAlignment="Right" Width="100" Height="20" Margin="3" Background="LightCyan" Content="Clear Search" vm:ButtonBehaviour.ClearCommand="{Binding ClearButtonPressed}"/> 
    </Grid> 
    <ListView Grid.Row="2" BorderBrush="Black" HorizontalAlignment="Stretch" ItemsSource="{Binding Path=AppCollection}" SelectedItem="{Binding SelectedApp}"> 
     <ListView.View> 
      <GridView> 
       <GridViewColumn Header="Application Name" Width="100" DisplayMemberBinding="{Binding Name}"/> 
       <GridViewColumn Header="Application Description" Width="800" DisplayMemberBinding="{Binding Description}"/> 
       <GridViewColumn Header="Application Owner" Width="100" DisplayMemberBinding="{Binding Owner}"/> 
      </GridView> 
     </ListView.View> 
    </ListView> 
    <Button Grid.Row="3" HorizontalAlignment="Center" Width="200" Height="30" Margin="3" Background="LightCyan" Content="Request Application" vm:ButtonBehaviour.EmailCommand="{Binding EmailButtonPressed}" /> 
</Grid> 

非常感謝!

回答

1

可以定義一個類RelayCommand,使您可以調用代表。用這種方法,你不需要爲每個Command聲明一個類。

public class RelayCommand : ICommand 
{ 
    #region Miembros 

    readonly Action<object> _execute; 
    readonly Predicate<object> _canExecute; 

    #endregion 

    #region Constructor 

    public RelayCommand(Action<object> execute) 
     : this(execute, null) 
    { 
    } 

    public RelayCommand(Action<object> execute, Predicate<object> canExecute) 
    { 
     if (execute == null) 
     { 
      throw new ArgumentNullException("execute"); 
     } 

     _execute = execute; 
     _canExecute = canExecute; 
    } 

    #endregion 

    #region Miembros de ICommand 

    public bool CanExecute(object parameter) 
    { 
     return _canExecute == null || _canExecute(parameter); 
    } 

    public event EventHandler CanExecuteChanged 
    { 
     add { CommandManager.RequerySuggested += value; } 
     remove { CommandManager.RequerySuggested -= value; } 
    } 

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

    #endregion 
} 

那麼你的視圖模型類將是這樣的:

public class ApplicationViewModel 
{ 
    public ObservableCollection<App> AppCollection { get; set; } 
    private string searchString; 
    private string emailString; 
    public App SelectedApp { get; set; } 
    public string AppToSearch 
    { 
     get 
     { 
      return searchString; 
     } 
     set 
     { 
      searchString = value; 
     } 
    } 
    public string AppToRequest 
    { 
     get 
     { 
      return emailString; 
     } 
     set { emailString = value; } 
    } 

    private ICommand searchButtonCmd; 
    private ICommand clearButtonCmd; 
    private ICommand emailButtonCmd; 

    public ApplicationViewModel() 
    { 
     this.AppCollection = ApplicationsModel.Current; 
    } 

    public ICommand SearchButtonPressed 
    { 
     get 
     { 
      if (this.searchButtonCmd == null) 
      { 
       this.searchButtonCmd = new RelayCommand(SearchButtonPressedExecute, c=>CanSearch); 
      } 
      return this.searchButtonCmd; 
     } 
    } 

    private void SearchButtonPressedExecute(object parameter) 
    { 
     ApplicationsModel.Current.Search(searchString); 
    } 

    public bool CanSearch 
    { 
     get { return true; } 
    } 

    // TODO: You can figure out the rest of the code 
} 

不要忘記更新您的按鈕的XAML,如:

<Button Grid.Row="0" Grid.Column="2" HorizontalAlignment="Right" Width="100" Height="20" Margin="3" Background="LightCyan" Content="Search" Command="{Binding SearchButtonPressed}" /> 

與同爲其他按鈕。

希望這會有所幫助!

+0

謝謝,那就是訣竅! – Herman404 2013-02-15 16:23:48

1

你可以在你的視圖模型委託或事件,你的命令類使用來獲得數據

..或者你可以通過命令參數的視圖命令傳遞數據。

Button Command="{Binding SaveCommand}" 
     CommandParameter="{Binding SelectedItem, Element=listBox}" /> 
相關問題