Об’єднуйте рядки замість того, щоб використовувати стек TextBlocks


88

Я хочу показати список об'єктів Клієнта в WPF ItemsControl. Я створив 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>

Отже, в основному я хочу це простий список (із прапорцями), який містить NUMBER - NAME. Хіба не існує способу, за допомогою якого я можу зв’язати номер та ім’я безпосередньо у частині, що пов’язує?

Відповіді:


171

Існує властивість StringFormat (у .NET 3.5 SP1), яким ви, мабуть, можете скористатися. І корисний чіт-код для зв’язування WPF можна знайти тут . Якщо це не допомагає, ви завжди можете написати власний ValueConverter або власну властивість для свого об'єкта.

Щойно встановивши прапорець, ви можете використовувати StringFormat з мультизв’язуванням. У вашому випадку код буде приблизно таким:

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

Мені довелося починати форматування рядка з простору, інакше Visual Studio не збирався будувати, але я думаю, ви знайдете спосіб обійти :)

Редагувати
Простір потрібен у форматі StringFormat, щоб парсер не розглядався {0}як справжнє прив'язування. Інші альтернативи:

<!-- 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}">

29
Замість простору ви можете використовувати {}, наприклад StringFormat = "{} {0} - {1}"
Брайан Андерсон,

6
Ви також можете вийти з фігурних дужок за допомогою зворотних скісних рисок: <MultiBinding StringFormat = "\ {0 \} - \ {1 \}">
hughdbrown

Також відсутній закриваючий TextBlock, тому, щоб підсумувати коментарі: <TextBlock> <TextBlock.Text> <MultiBinding StringFormat = "{} {0} - {1}"> <Binding Path = "Number" /> <Binding Path = "Name" /> </MultiBinding> </TextBlock.Text> </TextBlock>
TJKjaer,

@PiRX, якщо я хочу показати "номер", навіть якщо "ім'я" порожнє - як це зробити?
DasDas

@DasDas, на жаль, я не зможу допомогти з вашим запитанням, оскільки я кілька років не працював з WPF. Забавно, як швидко ти забуваєш речі, з якими вже не працюєш.
PiRX

64

Якщо ви хочете зв'язати динамічне значення зі статичним текстом, спробуйте наступне:

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

Дисплеї : 234-334-5566 (SSN)


1
Який вміст TextBlockLeftStyle?
ішо

Це нестандартний стиль, я повинен вирівняти блок тексту вліво. Тут це не має значення.
червоний череп

1
Це найкраще рішення для об’єднання прив’язки за допомогою рядка
Девід,

8

Дивіться наступний приклад, який я використав у своєму коді за допомогою класу 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 >

3

Ви також можете використовувати прив'язуваний прогін. Корисні речі, особливо якщо потрібно додати якесь форматування тексту (кольори, шрифт тощо).

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

Ось оригінальний клас:
Ось деякі додаткові вдосконалення.
І це все в одному шматку коду:

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);
        }
    }

1
<Запустити текст = "{Binding ...}" />? Ви можете пояснити переваги?
Фелікс Кейл

1
Без різниці; Запуск не підтримував прив'язки до властивості Text 10 років тому, коли була написана така відповідь!
josh2112
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.