web-dev-qa-db-fra.com

Lier un élément à deux sources

J'ai actuellement deux zones de texte qui acceptent n'importe quel nombre. J'ai un bloc de texte qui prend les deux nombres entrés et calcule la moyenne. 

Je me demandais s'il était possible de lier ce bloc de texte aux deux zones de texte et d'utiliser un convertisseur personnalisé pour calculer la moyenne. Je suis en train de saisir le texte modifié d'événements dans les deux zones de texte et de calculer la moyenne de cette façon, mais je suppose que la liaison des données serait plus efficace et plus simple.

37
Nick

Vous recherchez MultiBinding .

Votre XAML ressemblera à quelque chose comme ceci:

<TextBlock>
  <TextBlock.Text>
    <MultiBinding Converter="{StaticResource myConverter}">
      <Binding Path="myFirst.Value" />
      <Binding Path="mySecond.Value" />
    </MultiBinding>
  </TextBlock.Text>
</TextBlock>

Avec des remplacements raisonnables pour myConverter, myFirst.Value et mySecond.Value.

55
Jacob Carpenter

Créez un convertisseur qui implémente IMultiValueConverter. Cela pourrait ressembler à quelque chose comme ça:

class AverageConverter : IMultiValueConverter
{
    #region IMultiValueConverter Members
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        int total = 0;
        int number = 0;
        foreach (object o in values)
        {
            int i;
            bool parsed = int.TryParse(o.ToString(), out i);
            if (parsed)
            {
                total += i;
                number++;
            }
        }
        if (number == 0) return 0;
        return (total/number).ToString();
    }

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

    #endregion
}

Un convertisseur à plusieurs valeurs reçoit un tableau d'objets, un pour chacune des liaisons. Vous pouvez les traiter comme vous le souhaitez, selon que vous le souhaitiez pour double, int ou autre.

Si les deux zones de texte sont liées aux données, vous pouvez utiliser les mêmes liaisons dans la reliure multiple pour votre bloc de texte (en vous rappelant de notifier lorsque la propriété change afin que votre moyenne soit mise à jour) ou vous pouvez obtenir la valeur de texte en faisant référence aux zones de texte par ElementName.

<TextBox Text="{Binding Value1}" x:Name="TextBox1" />
<TextBox Text="{Binding Value2}" x:Name="TextBox2" />

<TextBlock>
   <TextBlock.Text>
      <MultiBinding Converter="{StaticResource AverageConverter}">
         <Binding ElementName="TextBox1" Path="Text" />
         <Binding ElementName="TextBox2" Path="Text" />
         <!--  OR  -->
         <!-- <Binding Path="Value1" />  -->
         <!-- <Binding Path="Value2" />  -->

      </MultiBinding>
   </TextBlock.Text>
</TextBlock>
35
Donnelle

Vous pouvez également créer une propriété dans le code situé derrière et y associer le TextBlock ... Je le fais tout le temps, et c'est un peu plus simple que de créer un convertisseur, puis de reproduire le même code ici.

Exemple: (dans votre code derrière le xaml):

public double AvgValue
{
    get { return (valueA + valueB) / 2.0; }
}

Et puis, dans votre XAML:

<TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=AvgValue}" />

C'est beaucoup plus simple qu'un convertisseur personnalisé.

2
Timothy Khouri

Juste pour ajouter une procédure étape par étape à la réponse de Timothy:

  1. Configurez la propriété View.TextBlock.Text pour qu'elle soit liée à la propriété ViewModel.AvgValue.
  2. Attrapez l'événement TextChanged du contrôle TextBox, puis définissez AvgValue dans le gestionnaire de cet événement TextChanged.
  3. En tant que partie de ce gestionnaire à l'étape 2, veillez à générer une modification de propriété afin que le TextBlock soit mis à jour.
0
Michael Nguyen