2011-08-07 7 views

答えて

1

通常、私はちょうどあなたがする必要はありません...言うの場としてのViewModelにtbLogin.TextとtbPassword.Textを渡すことができますどのように

<StackPanel Grid.Row="1" x:Name="spLogin"> 
      <TextBlock Text="E-mail:"></TextBlock> 
      <TextBox Name="tbLogin" Text="{Binding User.Email, Mode=TwoWay}"></TextBox> 
      <TextBlock Text="Password:"></TextBlock> 
      <TextBox Name="tbPassword" Text="{Binding User.Password, Mode=TwoWay}"></TextBox> 
      <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> 
       <Button Name="btnLogin" Content="Login"> 
        <Interactivity:Interaction.Triggers> 
         <Interactivity:EventTrigger EventName="Click" 
              x:Name="SelectChangeEvent"> 
          <Command:EventToCommand 
          Command="{Binding Login, Mode=TwoWay}" PassEventArgsToCommand="False" CommandParameter="{Binding}" /> 
         </Interactivity:EventTrigger> 
        </Interactivity:Interaction.Triggers> 
       </Button> 
       <Button Name="btnClear" Content="Clear"/> 
      </StackPanel> 
     </StackPanel> 
    </Grid> 

、 ViewModel(バインディングから推測される)はUserプロパティとLoginコマンドiselfの両方を含む必要があるため、コマンドのExcecuteメソッドからUserプロパティにアクセスすることができます。

しかし、あなたの提示したユーザークラスがINotifyPropertyChangedを実装していないことに気付きました。したがって、バインドが正しく機能しません。それを動作させるには、2つの可能性があります。

  1. ユーザクラスにINotifyPropertyChangedを実装してください。 - あなたのモデルとそれがどのように生成されるかによって、これは常に可能ではありません。
  2. ViewModelのプロパティを複製し、そこにINotifyPropertyChangedを実装してください。 - モデルの定義を制御できない場合(たとえば、Webサービスプロキシによって生成される場合など)、これが唯一の方法です。しかし、たとえあなたのモデルをコントロールしていても、このオプションはあなたのビューに渡されるものをより詳細に制御できるので、検討する価値があります。

ので、次のサンプルは、yoou 2番目のオプションのために行く前提としています

public class MvvmViewModel1 : ViewModelBase 
{ 
    private User _user; 

    #region [Login] 

    public const string LoginPropertyName = "Login"; 

    public string Login { 
     get { 
      return this._user.Login; 
     } 

     set { 
      if (this._user.Login == value) { 
       return; 
      } 

      var oldValue = this._user.Login; 
      this._user.Login = value; 

      RaisePropertyChanged(LoginPropertyName); 
     } 
    } 

    #endregion 

    #region [Password] 

    public const string PasswordPropertyName = "Password"; 

    public string Password { 
     get { 
      return this._user.Password; 
     } 

     set { 
      if (this._user.Password == value) { 
       return; 
      } 

      var oldValue = this._user.Password; 
      this._user.Password = value; 

      RaisePropertyChanged(PasswordPropertyName); 
     } 
    } 

    #endregion 

    #region [LoginCommand] 

    public RelayCommand _loginCommand; 

    public RelayCommand LoginCommand { 
     get { 
      return _loginCommand ?? (_loginCommand = new RelayCommand(
       () => { 
        // perform your login action here 
        // access Login with: this.Login 
        // access Password with: this.Password 
       }, 
       () => { 
        // can execute method - sample implementation 
        return (!string.IsNullOrEmpty(this.Login) && !string.IsNullOrEmpty(this.Password)); 
       } 
      )); 
     } 
    } 

    #endregion 
} 

明らかに、このビューモデルに一致するように、あなたのXAMLを変更する必要があります:

通常
<StackPanel Grid.Row="1" x:Name="spLogin"> 
    <TextBlock Text="E-mail:"></TextBlock> 
    <TextBox Name="tbLogin" Text="{Binding Login, Mode=TwoWay}"></TextBox> 
    <TextBlock Text="Password:"></TextBlock> 
    <TextBox Name="tbPassword" Text="{Binding Password, Mode=TwoWay}"></TextBox> 
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> 
     <Button Name="btnLogin" Content="Login"> 
      <Interactivity:Interaction.Triggers> 
       <Interactivity:EventTrigger EventName="Click" 
            x:Name="SelectChangeEvent"> 
        <Command:EventToCommand 
        Command="{Binding LoginCommand}" PassEventArgsToCommand="False" /> 
       </Interactivity:EventTrigger> 
      </Interactivity:Interaction.Triggers> 
     </Button> 
     <Button Name="btnClear" Content="Clear"/> 
    </StackPanel> 
</StackPanel> 

あなただけ必要CommandParameterを使用する場合は、データテンプレート(ListBox内のアイテムテンプレートなど)内にある場合および/またはコマンドとプロパティが同じVieにないwModel。あなたは、パラメータを受け入れるようにコマンドを定義する必要があり、この場合:

#region [LoginCommand] 

public RelayCommand _loginCommand; 

public RelayCommand LoginCommand { 
    get { 
     return _loginCommand ?? (_loginCommand = new RelayCommand(
      (p) => { 
       // perform your login action here 
      }, 
      (p) => { 
       // can execute method - sample implementation 
       return (!string.IsNullOrEmpty(this.Login) && !string.IsNullOrEmpty(this.Password)); 
      } 
     )); 
    } 
} 

#endregion 

そして今、あなたのViewModelにデータテンプレートのデータコンテキストを渡すためにあなたのXAML内

CommandParameter="{Binding}" 

を使用することができます。

もう1つの注意点:通常、双方向バインディングは必要ありません。ただし、ビューからViewModelに情報を書き戻したい場合は例外です。

サイドノートとして:XAMLでクラスを生成/変換することはできません。したがって、ViewModelにEmail/Passwordプロパティを持つUserクラスがある場合、XAMLの空白からLogin/Passwordプロパティを持つ新しいユーザークラスを作成し、それをViewModelに渡す方法はありません。バインドは強力ですが、全能ではありません... ;-)

+0

これはすばらしい答えでした。本当に有益な情報ですただし、UserResourcesにインスタンスを作成することはできません(それはお勧めできません)。 xml名前空間を定義し、 ''と '{StaticResource myUser}'を渡すのが好きですか? –

+0

ありがとう、嬉しいです。あなたは静的リソースを使って何をしたいのか分かりませんが、そうすることができます。しかし、上記のコードはもっと標準的な方法です。 – AxelEckenberger

+0

私はあなたに同意します。私は「あなたはXAMLのクラスを生成/変換できません...」と言ったことが技術的に正確であるかどうか疑問に思っていました。私はWPFが初めてです。ほとんどの場合、良いプログラミング方法になるとは限りません。私は理解が正しいことを確認したかっただけです。 –

0

tbLogin.TextとtbPassword.TextはUser.EmailとUser.Passwordに双方向でバインドされているため、CommandParameterをUserに簡単にバインドできます。より大きな質問は、なぜCommandParameterがすべて必要なのでしょうか?あなたのビューモデルはUserプロパティに直接アクセスできますか?

関連する問題