Verketten Sie Zeichenfolgen, anstatt einen Stapel TextBlocks zu verwenden

85

Ich möchte eine Liste von Kundenobjekten in einem WPF ItemsControl anzeigen. Ich habe eine DataTemplate dafür erstellt:

    <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>

Ich möchte also im Grunde eine einfache Liste (mit Kontrollkästchen), die NUMBER - NAME enthält. Gibt es nicht eine Möglichkeit, die Nummer und den Namen direkt im Bindungsteil zu verknüpfen?

Gerrie Schenck
quelle

Antworten:

168

Es gibt die StringFormat-Eigenschaft (in .NET 3.5 SP1), die Sie wahrscheinlich verwenden können. Und nützliche WPF-Bindungs-Cheat-Sheats finden Sie hier . Wenn dies nicht hilft, können Sie immer Ihren eigenen ValueConverter oder eine benutzerdefinierte Eigenschaft für Ihr Objekt schreiben.

Nur aktiviert, können Sie StringFormat mit Multibinding verwenden. In Ihrem Fall lautet der Code ungefähr so:

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

Ich musste den Formatstring mit Leerzeichen beginnen, sonst würde Visual Studio nicht erstellen, aber ich denke, Sie werden einen Weg finden, um das Problem zu umgehen :)

Bearbeiten
Der Speicherplatz im StringFormat wird benötigt, um zu verhindern, dass der Parser {0}als tatsächliche Bindung behandelt wird. Andere Alternativen:

<!-- 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
quelle
28
Anstelle des Leerzeichens können Sie {} verwenden, z. B. StringFormat = "{} {0} - {1}"
Bryan Anderson
6
Sie können die geschweiften Klammern auch mit umgekehrten Schrägstrichen umgehen: <MultiBinding StringFormat = "\ {0 \} - \ {1 \}">
hughdbrown
Außerdem fehlt der schließende TextBlock, um die Kommentare zusammenzufassen: <TextBlock> <TextBlock.Text> <MultiBinding StringFormat = "{} {0} - {1}"> <Binding Path = "Number" /> <Binding Path = "Name" /> </ MultiBinding> </TextBlock.Text> </ TextBlock>
TJKjaer
@PiRX wenn ich 'number' anzeigen möchte, auch wenn 'name' leer ist - wie mache ich das?
DasDas
@DasDas Leider kann ich Ihnen bei Ihrer Frage nicht weiterhelfen, da ich seit mehreren Jahren nicht mehr mit WPF zusammengearbeitet habe. Es ist lustig, wie schnell Sie Dinge vergessen, mit denen Sie nicht mehr arbeiten.
PiRX
63

Wenn Sie einen dynamischen Wert mit einem statischen Text verknüpfen möchten, versuchen Sie Folgendes:

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

Anzeigen : 234-334-5566 (SSN)

roter Schädel
quelle
1
Was ist der Inhalt von TextBlockLeftStyle?
itsho
Es ist ein benutzerdefinierter Stil, bei dem ich den Textblock nach links ausrichten muss. Es hat hier keine Bedeutung.
Redskull
1
Dies ist die beste Lösung, um eine Bindung mit einer Zeichenfolge zu verketten
Devid
8

Siehe das folgende Beispiel, das ich in meinem Code mit der Run-Klasse verwendet habe:

        <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
quelle
3

Sie können auch einen bindbaren Lauf verwenden. Nützliches, besonders wenn man eine Textformatierung hinzufügen möchte (Farben, Schriftgröße usw.).

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

Hier ist eine originelle Klasse:
Hier sind einige zusätzliche Verbesserungen.
Und das ist alles in einem 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
quelle
1
<Run Text = "{Binding ...}" />? Können Sie die Vorteile erklären?
Felix Keil
1
Kein Unterschied; Run hat vor 10 Jahren keine Bindungen für die Text-Eigenschaft unterstützt, als diese Antwort geschrieben wurde!
Josh2112