2 votes

Comment lier les données à des propriétés d'éléments spécifiques dans un ItemsControl de la manière la plus élégante ?

Scénario : Un ListView est lié par ses données à un ObservableCollection<CustomClass> et affiche ses éléments par le biais d'un ItemTemplate personnalisé. Le site CustomClass contient trois propriétés de type chaîne de caractères et une propriété de type booléen. INotifyPropertyChanged est déjà implémenté sur chacune de ses quatre propriétés. L'ItemTemplate personnalisé de la ListView a des liaisons à sens unique sur les trois propriétés de type chaîne et une liaison à sens unique sur la propriété booléenne, l'affichant comme une case à cocher.

Problème : Je cherche la manière la plus élégante (en termes de WPF) d'afficher le nombre de tous les éléments cochés dans ce ListView à l'aide d'un TextBlock - ou, en d'autres termes, tous les éléments dont la propriété booléenne est définie comme suit true dans cette collection. Je veux que ce bloc de texte mette immédiatement à jour le nombre affiché si l'un des éléments du ListView est coché/décoché. Je sais qu'il y a des façons (plutôt) laides d'y parvenir avec du code derrière et de l'eventhandling, mais j'aimerais savoir s'il y a une façon intelligente de faire cela peut-être complètement en XAML avec une syntaxe DataBinding obscure.

Edit : Juste à titre d'exemple/de clarification : Le ListView affiche 100 éléments, 90 éléments ont leur propriété booléenne définie sur true Le bloc de texte affichera donc '90'. Si l'utilisateur décoche un élément de plus dans la case à cocher et que, par conséquent, la propriété de cette dernière est définie comme suit false par l'intermédiaire de la liaison bidirectionnelle, le bloc de texte devrait être mis à jour en '89'.

2voto

Jehof Points 14720

Vous pouvez utiliser un convertisseur pour construire une chaîne de caractères avec le nombre d'éléments cochés.

public sealed class CountToStringConverter : System.Windows.Data.IValueConverter {
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
        ObservableCollection<CustomClass> items = value as ObservableCollection<CustomClass>;

        int count = 0;

        foreach (var item in items) {
            if (item.IsChecked) {
                count++;
            }
        }

        return count + " Items";
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
        throw new NotImplementedException();
    }

    #endregion
}

Liez la propriété Text de la TextBox à la collection.

<TextBox Text={Binding Items, Converter={StaticResource countToStringConverter}}/>

UPDATE : Cette liaison ne fonctionne que si les éléments de propriété déclenchent l'événement PropertyChanged, si la collection est modifiée.

2voto

Simon Steele Points 8344

Personnellement, j'effectuerais probablement cette opération dans mon ViewModel. Souscrivez à la propriété modifiée sur les éléments de l'ObservableCollection, puis signalez la propriété Count modifiée sur le ViewModel chaque fois que la propriété booléenne change. Dans votre vue, il suffit de se lier à la propriété Count.

0voto

KeithS Points 36130

S'il s'agissait d'un simple formulaire ASP.NET, j'envisagerais d'utiliser JQuery pour compter les éléments sélectionnés dans la ListBox. C'est peut-être encore une option viable dans WPF :

var count = 0;
$('#multiItemListBox :selected').each(count++);

Insérez ce code dans un gestionnaire d'événement JS pour l'événement OnChange de la ListBox. Vous devez savoir comment la ListBox est appelée dans le HTML que le client reçoit, et je ne suis pas sûr de la façon dont WPF les mélange ou de la façon de coller la référence correcte dans le XAML côté serveur.

0voto

naacal Points 500

Merci pour toutes les réponses que j'ai reçues, ce sont toutes des solutions applicables mais malheureusement pas vraiment ce que j'ai essayé d'obtenir. Voici donc comment j'ai résolu le problème :

J'ai implémenté une DependencyProperty sur la fenêtre contenant le bloc de texte :

public static readonly DependencyProperty ActiveItemCountProperty =
        DependencyProperty.Register("ActiveItemCount", typeof(int), typeof(CustomControl), new UIPropertyMetadata(0));

Sur le DataTemplate des éléments de la ListView, la CheckBox a enregistré un EventHandler pour le Click-Event :

<CheckBox IsChecked="{Binding Active, Mode=TwoWay}" Click="CheckBox_Click" />

Le gestionnaire d'événement dans le code derrière ressemble à quelque chose comme ceci :

    private void CheckBox_Click(object sender, RoutedEventArgs e)
    {
        ObservableCollection<CustomClass> sourceCol = listView.DataContext as ObservableCollection<CustomClass>;
        if (sourceCol != null)
            ActiveItemCount = sourceCol.Count(x => x.Active);
    }

Et évidemment, le bloc de texte est juste une donnée liée à cette DependencyProperty :

<TextBlock Text="{Binding Path=ActiveItemCount, ElementName=ControlRoot}" />

ControlRoot étant le nom de la fenêtre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X