2010-08-30 4 views
2

Dans une application Silverlight MVVMLight 4.0, j'ai une zone de liste, une zone de texte et une case à cocher. ItemsSource de listbox est lié à une liste d'objets dans le viewmodel. L'élément SelectedItem de la liste est lié à un objet (SelectedActivity) dans le viewmodel.Silverlight MVVM - Liaison bidirectionnelle non déclenchée sur Listbox cliquez sur

Le texte de la zone de texte et les propriétés IsSelected de la case à cocher sont liés dans les deux sens à l'objet SelectedActivity (propriétés Name et Selected) dans le viewmodel. Il n'y a pas codebehind. Cela fonctionne très bien: changer le nom dans la zone de texte ou cocher/décocher la case puis tabuler changera la propriété sous-jacente de l'objet.

Mais lorsque je change le nom (ou l'état coché) puis clique immédiatement sur un autre élément de la liste, la modification n'est pas enregistrée.

Est-ce que quelqu'un a une solution de contournement pour cela?

salutations les,

Karel

C'est le XAML:

<ListBox Height="251" HorizontalAlignment="Left" Margin="11,39,0,0" Name="activitiesListBox" ItemsSource="{Binding Activities.Items}" VerticalAlignment="Top" Width="139" 
      SelectedItem="{Binding Activities.SelectedActivity, Mode=TwoWay}"> 

Ceci est la classe Activités tenant les éléments liés à la liste:

public class CLJActivitiesViewModel : ViewModelBase 
{ 
    /// <summary> 
    /// Initializes a new instance of the ActivitiesViewModel class. 
    /// </summary> 
    public CLJActivitiesViewModel() 
    { 
     ////if (IsInDesignMode) 
     ////{ 
     //// // Code runs in Blend --> create design time data. 
     ////} 
     ////else 
     ////{ 
     //// // Code runs "for real": Connect to service, etc... 
     ////} 
    } 


    #region items 
    /// <summary> 
    /// The <see cref="Items" /> property's name. 
    /// </summary> 
    public const string ItemsPropertyName = "Items"; 

    private ObservableCollection<CLJActivityViewModel> m_Items = null; 

    /// <summary> 
    /// Gets the Items property. 
    /// TODO Update documentation: 
    /// Changes to that property's value raise the PropertyChanged event. 
    /// This property's value is broadcasted by the Messenger's default instance when it changes. 
    /// </summary> 
    public ObservableCollection<CLJActivityViewModel> Items 
    { 
     get 
     { 
      return m_Items; 
     } 

     set 
     { 
      if (m_Items == value) 
      { 
       return; 
      } 

      var oldValue = m_Items; 
      m_Items = value; 

      RaisePropertyChanged(ItemsPropertyName, oldValue, value, true); 
     } 
    } 
    #endregion 

    #region SelectedActivity 
    /// <summary> 
    /// The <see cref="SelectedActivity" /> property's name. 
    /// </summary> 
    public const string SelectedActivityPropertyName = "SelectedActivity"; 

    private CLJActivityViewModel m_SelectedActivity = null; 

    /// <summary> 
    /// Gets the SelectedActivity property. 
    /// TODO Update documentation: 
    /// Changes to that property's value raise the PropertyChanged event. 
    /// This property's value is broadcasted by the Messenger's default instance when it changes. 
    /// </summary> 
    public CLJActivityViewModel SelectedActivity 
    { 
     get 
     { 
      return m_SelectedActivity; 
     } 

     set 
     { 
      if (m_SelectedActivity == value) 
      { 
       return; 
      } 

      var oldValue = m_SelectedActivity; 
      m_SelectedActivity = value; 

      RaisePropertyChanged(SelectedActivityPropertyName, oldValue, value, true); 
     } 
    } 
    #endregion 



    public override void Cleanup() 
    { 
     // Clean own resources if needed 

     base.Cleanup(); 
    } 
}   
+0

Il serait utile si vous avez publié au moins la partie pertinente de votre code viewmodel/view. Votre liste est-elle un ObservableCollection et votre viewmodel implémentant INotifyPropertyChanged? –

+0

Oui, la liste est liée à une ObservableCollection et le viewmodel implémente INotifyPropertyChanged. J'ai utilisé les modèles MVVMLight. Je vais mettre à jour la question avec le code approprié. – Karel

Répondre

1

J'ai rencontré le même problème. J'ai dû déclencher la mise à jour lorsque l'utilisateur entrait du texte afin que je puisse faire une validation.

Un moyen facile d'y parvenir est de créer un comportement personnalisé que vous pouvez ensuite ajouter à TextBox.

mine est la suivante:

public static class TextChangedBindingBehavior 
{ 
    public static readonly DependencyProperty InstanceProperty = 
     DependencyProperty.RegisterAttached("Instance", typeof(object), typeof(TextChangedBindingBehavior), new PropertyMetadata(OnSetInstanceCallback)); 


    public static object GetInstance(DependencyObject obj) 
    { 
     return (object)obj.GetValue(InstanceProperty); 
    } 

    public static void SetInstance(DependencyObject obj, object value) 
    { 
     obj.SetValue(InstanceProperty, value); 
    } 

    private static void OnSetInstanceCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var textBox = d as TextBox; 
     if (textBox != null) 
     { 
      textBox.TextChanged -= OnTextChanged; 
      textBox.TextChanged += OnTextChanged; 
     } 
    } 

    private static void OnTextChanged(object sender, TextChangedEventArgs e) 
    { 
     var textBox = (TextBox)sender; 

     if(!DesignerProperties.GetIsInDesignMode(textBox)) 
     { 
      textBox.GetBindingExpression(TextBox.TextProperty).UpdateSource(); 
     } 
    } 
} 

et vous définissez au TextBox comme ça (Behaviors est l'espace de noms où je mets la classe ci-dessus):

<TextBox Behaviors:TextChangedBindingBehavior.Instance="" Text="{Binding Name, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" /> 
+0

Merci, je vais essayer ça. – Karel

+0

Super, ça marche parfaitement! – Karel

1

Je J'ai rencontré le problème avec TextBox, mais je ne l'ai pas vu affecter la case à cocher. Le problème TextBox se produit parce que le texte lié est mis à jour, puis le focus est perdu. C'est pourquoi si vous tabulez d'abord, puis modifiez votre sélection, cela fonctionne comme prévu. Si vous modifiez la sélection, le texte directement lié ne sera pas mis à jour car le message de mise au point perdue arrive trop tard. Une façon de résoudre ce problème consiste à forcer la mise à jour de la liaison chaque fois que l'utilisateur tape du texte dans la zone de texte. Vous pouvez faire un comportement personnalisé pour le garder mvvm.

Questions connexes