Połącz łańcuchy zamiast używać stosu TextBlocks

88

Chcę pokazać listę obiektów Customer w WPF ItemsControl. Utworzyłem w tym celu DataTemplate:

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

To, czego chcę, to w zasadzie prosta lista (z polami wyboru), która zawiera NUMER - NAZWA. Czy nie ma sposobu, w jaki mogę połączyć numer i nazwę bezpośrednio w części Binding?

Gerrie Schenck
źródło

Odpowiedzi:

171

Istnieje właściwość StringFormat (w .NET 3.5 SP1), której prawdopodobnie możesz użyć. A użyteczną powłokę do ściągania wiązań WPF można znaleźć tutaj . Jeśli to nie pomoże, zawsze możesz napisać własny ValueConverter lub niestandardową właściwość dla swojego obiektu.

Właśnie zaznaczone, możesz użyć StringFormat z multibindingu. W twoim przypadku kod będzie wyglądał mniej więcej tak:

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

Musiałem zacząć format string od spacji, inaczej Visual Studio by się nie zbudował, ale myślę, że znajdziesz sposób na obejście tego :)

Edycja
Miejsce jest potrzebne w StringFormat, aby parser nie traktował go {0}jako rzeczywistego powiązania. Inne alternatywy:

<!-- 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
źródło
29
Zamiast spacji możesz użyć {}, np. StringFormat = "{} {0} - {1}"
Bryan Anderson
6
Możesz również zmienić znaczenie nawiasów klamrowych za pomocą odwrotnych ukośników: <MultiBinding StringFormat = "\ {0 \} - \ {1 \}">
hughdbrown,
Brakuje również zamykającego TextBlock, więc podsumowując komentarze: <TextBlock> <TextBlock.Text> <MultiBinding StringFormat = "{} {0} - {1}"> <Binding Path = "Number" /> <Binding Path = "Name" /> </MultiBinding> </TextBlock.Text> </TextBlock>
TJKjaer
@PiRX, jeśli chcę pokazać „numer”, nawet jeśli „nazwa” jest pusta - jak mam to zrobić?
DasDas
@DasDas niestety nie będę w stanie odpowiedzieć na twoje pytanie, ponieważ nie pracowałem z WPF od kilku lat. To zabawne, jak szybko zapominasz o rzeczach, nad którymi już nie pracujesz.
PiRX
64

Jeśli chcesz połączyć wartość dynamiczną z tekstem statycznym, spróbuj tego:

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

Wyświetlacze : 234-334-5566 (SSN)

czerwona Czaszka
źródło
1
Jaka jest zawartość TextBlockLeftStyle?
itsho
Jest to niestandardowy styl, w którym muszę wyrównać blok tekstowy do lewej. Nie ma tu znaczenia.
redskull
1
To najlepsze rozwiązanie, aby połączyć wiązanie z łańcuchem
Devid
8

Zobacz następujący przykład, którego użyłem w moim kodzie przy użyciu klasy 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
źródło
3

Możesz także użyć pliku run, który można powiązać. Przydatne rzeczy, zwłaszcza jeśli chce się dodać trochę formatowania tekstu (kolory, grubość czcionki itp.).

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

Oto oryginalna klasa:
Oto kilka dodatkowych ulepszeń.
A to wszystko w jednym kawałku kodu:

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
źródło
1
<Run Text = "{Binding ...}" />? Czy możesz wyjaśnić zalety?
Felix Keil
1
Bez różnicy; Run nie obsługiwał powiązań we właściwości Text 10 lat temu, kiedy napisano tę odpowiedź!
josh2112