2015-10-02 48 views
2

我是xaml,WPF,C#和MVVM範例的新手。我已經開始使用一個基於this example project的應用程序,在選定的摘錄中,我想在單擊身份驗證按鈕(如果您通過身份驗證後沒有點擊按鈕)從LoginPageViewModel中禁用身份驗證按鈕。我有命令綁定工作,以及視圖和ViewModel之間的文本控件綁定。我的LoginPageViewModel是基於從INotifyPropertyChanged繼承的抽象類錯誤綁定isEnabled按鈕在xaml

setter AuthenticateButtonEnabled正在工作,但它沒有綁定到窗體上的isEnabled proprerty。我的問題是,我可能錯過了什麼,以及如何跟蹤View和ViewModel之間的綁定?

的LoginPageView.xaml按鈕:

 <Button x:Name="authenticateButton" Content="{x:Static res:Strings.LoginPage_authenticateButton_content}" 
      Grid.Column="2" Margin="53,4,0,10" 
      Grid.Row="2" FontSize="16" 
      IsEnabled="{Binding Path=AuthenticateButtonEnabled}" 
      Command="{Binding Path=AuthenticateCommand}" HorizontalAlignment="Left" Width="87"/> 

視圖模型

private String _username; 
    private String _responseTextBlock; 
    private String _linkTextBlockURI; 
    private String _linkTextBlockText; 
    private bool _authenticateButtonEnabled; 
    ... 
    private async void Authenticate() 
    { 
     ResponseTextBlock = Strings.LoginPage_responseBlock_content_checking;#this works! 
     AuthenticateButtonEnabled = false; 
     return; 

    } 
    .... 

    public bool AuthenticateButtonEnabled 
    { 
     get { return _authenticateButtonEnabled; } 
     set { _authenticateButtonEnabled = value; OnPropertyChanged("AuthenticateButtonEnabled"); } 
    } 
    // this is in the abstract class. 
    protected virtual void OnPropertyChanged(string propertyName) 
    { 
     PropertyChangedEventHandler handler = this.PropertyChanged; 
     if (handler != null) 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 

回答

1

如果你想有兩個:命令和AuthenticateButtonEnabled,然後簡單地檢查該物業在CanExecute委託,反之亦然在屬性setter更新命令。

這是實現與DelegateCommand和一些改進,可能對您有用:

bool _isAuthenticateButtonEnabled; 
public bool IsAuthenticateButtonEnabled 
{ 
    get { return _isAuthenticateButtonEnabled; } 
    set 
    { 
     _isAuthenticateButtonEnabled = value; 
     OnPropertyChanged(); 
     AuthenticateCommand.Update(); 
    } 
} 

// the base could class could actually implement this 
void OnPropertyChanged([CallerMemberName] string property) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property)); 

public DelegateCommand AuthenticateCommand { get; } 

// view model constructor 
public ViewModel() 
{ 
    AuthenticateCommand = new DelegateCommand(o => 
    { 
     ... // some actions when command is executed 
    }, o => 
    { 
     bool somecondition = ...; // some condition to disable button, e.q. when executing command 
     return somecondition && IsAuthenticateButtonEnabled; 
    }); 
} 

這將讓你同時擁有:屬性啓用/禁用按鈕,它可以結合使用(另一個控制,例如CheckBox.IsChecked)和命令可以有獨立的條件來禁用命令時不應該執行按鈕(通常在async命令委託,當它執行長時間運行的命令,但爲此,你可能想檢查this答案。)。

+0

Sinatr感謝您的建議,我覺得很沮喪使用這個MVVM範例 - 一個簡單的.enabled = false已經讓我在一天中實現了更好的一部分 - 我不禁想到範式太複雜,無法使用.....確定從演示文稿抽象邏輯是好的,但我不禁認爲它應該更容易.... – pgee70

1

,如果你綁定按鈕在您的視圖模型的命令屬性設置爲一個ICommand的屬性,那麼你並不需要處理該按鈕的IsEnabled屬性,因爲它由ICommand實現的CanExecute方法處理。

谷歌的RelayCommand或DelegateCommand

0

感謝海報的幫助,我想爲他人分享工作解決方案。我使用了DelegateCommand,但必須更改loginPageViewModel中的某些部分才能使其工作:我還更新了xaml,以便控件在成功驗證後都處於非活動狀態。

的loginPage XAML:

<Label x:Name="usernameLabel" Content="{x:Static res:Strings.LoginPage_usernameLabel_content}" HorizontalAlignment="Left" Margin="10,4,0,0" Grid.Row="0" VerticalAlignment="Top" Width="130" FontSize="16" Height="36" Grid.Column="1"/> 
    <TextBox x:Name="usernameTextBox" Grid.Column="2" Grid.Row="0" TextWrapping="Wrap" 
      Text="{Binding Username, UpdateSourceTrigger=PropertyChanged}" 
      IsEnabled="{Binding AuthenticateButtonEnabled}" 
      Margin="10,5,0,6" FontSize="16" HorizontalAlignment="Left" Width="130" TextChanged="usernameTextBox_TextChanged"/> 
    <Label x:Name="passwordLabel" Content="{x:Static res:Strings.LoginPage_passwordLabel_content}" Margin="10,5,0,0" Grid.Row="1" VerticalAlignment="Top" FontSize="16" Height="36" Grid.RowSpan="2" HorizontalAlignment="Left" Width="130" Grid.Column="1"/> 
    <PasswordBox x:Name="passwordBox" Grid.Column="2" Margin="10,0,0,9" 
     PasswordChanged="PasswordBox_PasswordChanged" 
     IsEnabled="{Binding AuthenticateButtonEnabled}" 
     Grid.Row="1" FontSize="16" HorizontalAlignment="Left" Width="130"/> 
    <Button x:Name="authenticateButton" Content="{x:Static res:Strings.LoginPage_authenticateButton_content}" 
      Grid.Column="2" Margin="53,4,0,10" 
      Grid.Row="2" FontSize="16" 
      IsEnabled="{Binding AuthenticateButtonEnabled}" 
      Command="{Binding Path=AuthenticateCommand}" HorizontalAlignment="Left" Width="87"/> 

的loginPageViewModel:

.... 
    private bool _authenticateButtonEnabled; 
    private DelegateCommand _authenticateCommand; 
    public bool AuthenticateButtonEnabled { 
     get { return _authenticateButtonEnabled; } 
     set 
     { 
      _authenticateButtonEnabled = value; 
      DynamicOnPropertyChanged(); // this is so named to not content with onPropertyChanged defined elsewhere. 
      AuthenticateCommand.Update(); 
     } 
    } 
    ... 

    public DelegateCommand AuthenticateCommand 
    { 
     get { 
      if (_authenticateCommand == null) 
      { 
       _authenticateCommand = new DelegateCommand(Authenticate, AuthenticateEnded); 
      } 
      return _authenticateCommand; 
     } 
    } 
    private bool AuthenticateEnded(object obj) { 
     return _authenticateButtonEnabled; 
    } 
    private async void Authenticate(object obj) 
    { 
     AuthenticateButtonEnabled = false; 

     ResponseTextBlock = Strings.LoginPage_responseBlock_content_checking; 
     i3SoftHttpClient _httpClient = new i3SoftHttpClient(); 
     i3SoftUser _i3SoftUser; 
     AuthenticateCommand.CanExecute(false); 
     .... 
     // if authentication does not succeed - turn the buttons back on. 
     AuthenticateCommand.CanExecute(true); 
    } 

並向Delegate command class我說:

public void Update() 
    { 
     if (CanExecuteChanged != null) 
      CanExecuteChanged(this, EventArgs.Empty); 
    }