2010-05-02 7 views
4

J'ai une page WM7 simple avec un TextBox. De plus, j'ai affecté EventToCommand (un RelayCommand<string>) à ce TextBox, en réaction à l'événement TextChanged. Pour tester des fins, j'ai fait la méthode supplémentaire TextBox_TextChanged dans le code de la page derrière. La commande et TextBox_TextChanged impriment une boîte de message avec le contenu de la zone de texte. La valeur initiale de TextBox est "ABC". Ensuite, je presse D et:MVVM Light est trop rapide :)

  1. TextBox_TextChanged imprime ABCD.
  2. La commande imprime ABC. D est manquant.

Pourquoi la commande est-elle si rapide?

Déclaration de commande:

public RelayCommand<string> TextChanged {get; private set;} 

initialisation de commande:

TextChanged = new RelayCommand<string>((s) => MessageBox.Show(s)); 

Commande de liaison:

<TextBox x:Name="SearchTextBox" Margin="10,0" TextWrapping="Wrap" Text="{Binding SearchString, Mode=TwoWay}" FontStyle="Italic" TextChanged="SearchTextBox_TextChanged" > 
    <i:Interaction.Triggers> 
     <i:EventTrigger EventName="TextChanged"> 
      <GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding TextChanged, Mode=OneWay}" CommandParameter="{Binding Text, ElementName=SearchTextBox}"/> 
     </i:EventTrigger> 
    </i:Interaction.Triggers> 
</TextBox> 
+0

Pouvez-vous poster votre code? Il est difficile de savoir à coup sûr sans voir comment tout est relié ensemble. – Oded

+0

une question est ici? –

+0

Par WM7 voulez-vous dire Windows Phone 7? –

Répondre

6

Je ne peux pas reproduire ce comportement. J'ai essayé d'utiliser EventToCommand et un comportement (qui écoute simplement l'événement TextChanged).

Sans voir le code, je soupçonne que cela peut être dû à la façon dont vous obtenez le texte de la boîte de recherche ou une erreur de logique ailleurs.

C'est un extrait de la façon dont je l'utilise EventToCommand:

<TextBox Name="SearchTextBox"> 
    <i:Interaction.Triggers> 
    <i:EventTrigger EventName="TextChanged"> 
     <cmd:EventToCommand Command="{Binding TestTextChangedCommand,Mode=OneWay}" CommandParameter="{Binding Path=Text, ElementName=SearchTextBox}"/> 
    </i:EventTrigger> 
    <i:Interaction.Triggers> 
</TextBox> 

Dans le viewmodel

m_TestTextChangedCommand = new RelayCommand<string>(val => System.Diagnostics.Debug.WriteLine(val)); 

Comme vous pouvez le voir, j'utilisé un CommandParameter pour passer la valeur de la zone de texte à la viewmodel. De cette façon, le viewmodel n'a pas besoin de connaître la zone de texte pour obtenir la valeur du texte.

Une alternative à cette approche serait d'utiliser les comportements et TwoWay lier à mettre à jour une propriété:

<TextBox Name="SearchTextBox" Text="{Binding TextInViewModel, Mode=TwoWay}" > 
    <i:Interaction.Behaviors> 
    <sc:UpdateOnTextChangedBehavior/> 
    </i:Interaction.Behaviors> 
</TextBox> 

classe UpdateOnTextChangedBehavior:

public class UpdateOnTextChangedBehavior : Behavior<TextBox> 
    { 
     protected override void OnAttached() 
     { 
      base.OnAttached(); 

      this.AssociatedObject.TextChanged += 
       new TextChangedEventHandler(AssociatedObject_TextChanged); 
     } 

     void AssociatedObject_TextChanged(object sender, TextChangedEventArgs e) 
     { 
      System.Diagnostics.Debug.WriteLine(((TextBox)sender).Text); 
      BindingExpression binding = 
       this.AssociatedObject.GetBindingExpression(TextBox.TextProperty); 
      if (binding != null) 
      { 
       binding.UpdateSource(); 
      } 
     } 

     protected override void OnDetaching() 
     { 
      base.OnDetaching(); 

      this.AssociatedObject.TextChanged -= 
       new TextChangedEventHandler(AssociatedObject_TextChanged); 
     } 
    } 

Ce que le ci-dessus est miment le comportement de WPF de bureau Binding avec UpdateSourceTrigger=PropertyChanged, qui est manquant dans Silverlight. Alors que se passera-t-il, à chaque fois que vous tapez dans la zone de texte TextInViewModel la propriété sera mise à jour. Cette propriété n'a pas la valeur DependencyProperty, il pourrait s'agir d'une propriété CLR normale.

+0

Merci! Ca marche comme un charme, ça m'a beaucoup aidé – J4N

0

Certains code, je poursuivi en justice (semblable à la vôtre exemple de commande):

Déclaration de commande:

public RelayCommand<string> TextChanged {get; private set;} 

initialisation de commande:

TextChanged = new RelayCommand<string>((s) => MessageBox.Show(s)); 

de liaison de commande:

<TextBox x:Name="SearchTextBox" Margin="10,0" TextWrapping="Wrap" Text="{Binding SearchString, Mode=TwoWay}" FontStyle="Italic" TextChanged="SearchTextBox_TextChanged" > 
<i:Interaction.Triggers> 
    <i:EventTrigger EventName="TextChanged"> 
     <GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding TextChanged, Mode=OneWay}" CommandParameter="{Binding Text, ElementName=SearchTextBox}"/> 
    </i:EventTrigger> 
</i:Interaction.Triggers> 

Pour certaines raisons, la boîte de message affiche une chaîne avec un retard de caractère.

+0

Bienvenue sur stackOverflow! Notez que vous ne devriez pas poster de réponses comme réponses ici, soit utiliser des commentaires ou modifier le message original, les réponses n'ont pas d'ordre. –

1

Cela fonctionne avec TextBox via le paramètre pour RelayCommand. OIEau - RelayCommand<TextBox>

<TextBox Height="72" HorizontalAlignment="Left" Margin="8,136,0,0" Name="txtFilter" Text="" VerticalAlignment="Top" Width="460" > 
     <interactivity:Interaction.Triggers> 
      <interactivity:EventTrigger EventName="TextChanged"> 
       <cmd:EventToCommand Command="{Binding SearchedTextChanged}" CommandParameter="{Binding ElementName=txtFilter}" /> 
      </interactivity:EventTrigger> 
     </interactivity:Interaction.Triggers> 
    </TextBox> 

public RelayCommand<TextBox> SearchedTextChanged { get; set; } 

SearchedTextChanged = new RelayCommand<TextBox>(OnSearchedTextChanged); 

private void OnSearchedTextChanged(TextBox val) 
    { 
     if (val != null) 
     { 
      System.Diagnostics.Debug.WriteLine(val.Text); 
     } 
    } 
1

J'ai eu un problème similaire et a constaté que l'opération de liaison de données ne se déclenche pas toujours jusqu'à ce que la zone de texte perd le focus. Cependant, la commande tirera immédiatement.

Si vous voulez garantir que la liaison de données a bien eu lieu avant d'utiliser la valeur, vous pouvez appeler la méthode BindingExpression.UpdateSource() sur votre contrôle. Essayez quelque chose comme ceci:

var bindTarget = SearchTextBox.GetBindingExpression(TextBox.TextProperty); 
bindTarget.UpdateSource(); 

Pour éviter de se référer à votre zone de texte directement dans votre ViewModel (comme vous devriez avec MVVM), vous pouvez utiliser FocusManager.GetFocusedElement(). Ceci est particulièrement utile lorsque vous manipulez les boutons ApplicationBar car ils ne semblent pas recevoir de focus lorsqu'ils sont utilisés.

Questions connexes