Concaténer les chaînes au lieu d'utiliser une pile de TextBlocks

88

Je souhaite afficher une liste d'objets Customer dans un WPF ItemsControl. J'ai créé un DataTemplate pour cela:

    <DataTemplate DataType="{x:Type myNameSpace:Customer}">
        <StackPanel Orientation="Horizontal" Margin="10">
            <CheckBox"></CheckBox>
            <TextBlock Text="{Binding Path=Number}"></TextBlock>
            <TextBlock Text=" - "></TextBlock>
            <TextBlock Text="{Binding Path=Name}"></TextBlock>
        </StackPanel>
    </DataTemplate>

Donc, ce que je veux, c'est une simple liste (avec des cases à cocher) qui contient NUMBER - NAME. N'existe-t-il pas un moyen de concaténer le numéro et le nom directement dans la partie Reliure?

Gerrie Schenck
la source

Réponses:

171

Il existe une propriété StringFormat (dans .NET 3.5 SP1), que vous pouvez probablement utiliser. Et le sheat de triche de liaison WPF utile peut être trouvé ici . Si cela ne vous aide pas, vous pouvez toujours écrire votre propre ValueConverter ou une propriété personnalisée pour votre objet.

Juste coché, vous pouvez utiliser StringFormat avec la multi-liaison. Dans votre cas, le code ressemblera à ceci:

<TextBlock>
  <TextBlock.Text>
    <MultiBinding StringFormat=" {0} - {1}">
        <Binding Path="Number"/>
        <Binding Path="Name"/>
    </MultiBinding>
  </TextBlock.Text>
</TextBlock>

J'ai dû commencer la chaîne de format avec de l'espace, sinon Visual Studio ne serait pas construit, mais je pense que vous trouverez un moyen de le contourner :)

Edit
L'espace est nécessaire dans le StringFormat pour empêcher l'analyseur de traiter {0}comme une liaison réelle. Autres alternatives:

<!-- use a space before the first format -->
<MultiBinding StringFormat=" {0} - {1}">

<!-- escape the formats -->
<MultiBinding StringFormat="\{0\} - \{1\}">

<!-- use {} before the first format -->
<MultiBinding StringFormat="{}{0} - {1}">
PiRX
la source
29
Au lieu de l'espace, vous pouvez utiliser {}, par exemple StringFormat = "{} {0} - {1}"
Bryan Anderson
6
Vous pouvez également échapper les accolades avec des barres obliques inverses: <MultiBinding StringFormat = "\ {0 \} - \ {1 \}">
hughdbrown
De plus, le TextBlock de fermeture est manquant, donc pour résumer les commentaires: <TextBlock> <TextBlock.Text> <MultiBinding StringFormat = "{} {0} - {1}"> <Binding Path = "Number" /> <Binding Path = "Name" /> </MultiBinding> </TextBlock.Text> </TextBlock>
TJKjaer
@PiRX si je veux afficher 'numéro' même si 'nom' est vide - comment faire?
DasDas
@DasDas, malheureusement, je ne pourrai pas répondre à votre question car je n'ai pas travaillé avec WPF depuis plusieurs années. C'est drôle à quelle vitesse vous oubliez des choses avec lesquelles vous ne travaillez plus.
PiRX
64

Si vous souhaitez concaténer une valeur dynamique avec un texte statique, essayez ceci:

<TextBlock Text="{Binding IndividualSSN, StringFormat= '\{0\} (SSN)'}"/>

Écrans : 234-334-5566 (SSN)

crâne Rouge
la source
1
Quel est le contenu de TextBlockLeftStyle?
itsho
C'est un style personnalisé que je dois aligner le bloc de texte à gauche. Cela n'a aucune signification ici.
redskull
1
C'est la meilleure solution pour concaténer une liaison avec une chaîne
Devid
8

Voir l'exemple suivant que j'ai utilisé dans mon code à l'aide de la classe Run:

        <TextBlock x:Name="..." Width="..." Height="..."
            <Run Text="Area="/>
            <Run Text="{Binding ...}"/>
            <Run Text="sq.mm"/>
            <LineBreak/>
            <Run Text="Min Diameter="/>
            <Run Text="{Binding...}"/>
            <LineBreak/>
            <Run Text="Max Diameter="/>
            <Run Text="{Binding...}"/>
        </TextBlock >
user3262530
la source
3

Vous pouvez également utiliser une exécution pouvant être liée. Des trucs utiles, surtout si l'on veut ajouter un peu de mise en forme du texte (couleurs, épaisseur de police etc.).

<TextBlock>
   <something:BindableRun BoundText="{Binding Number}"/>
   <Run Text=" - "/>
   <something:BindableRun BoundText="{Binding Name}"/>
</TextBlock>

Voici une classe originale:
voici quelques améliorations supplémentaires.
Et c'est tout dans un seul morceau de code:

public class BindableRun : Run
    {
        public static readonly DependencyProperty BoundTextProperty = DependencyProperty.Register("BoundText", typeof(string), typeof(BindableRun), new PropertyMetadata(new PropertyChangedCallback(BindableRun.onBoundTextChanged)));

        private static void onBoundTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((Run)d).Text = (string)e.NewValue;
        }

        public String BoundText
        {
            get { return (string)GetValue(BoundTextProperty); }
            set { SetValue(BoundTextProperty, value); }
        }

        public BindableRun()
            : base()
        {
            Binding b = new Binding("DataContext");
            b.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(FrameworkElement), 1);
            this.SetBinding(DataContextProperty, b);
        }
    }
cz_dl
la source
1
<Run Text = "{Binding ...}" />? Pouvez-vous expliquer les avantages?
Felix Keil
1
Aucune différence; Run ne prenait pas en charge les liaisons sur la propriété Text il y a 10 ans lorsque cette réponse a été écrite!
josh2112