Амперсанд в формате StringFormat привязки WPF

Я пытаюсь создать строковый формат, в котором есть буквальная строка, содержащая амперсанд. Я пробовал & и & amp; (без пробела), но оба вызывают исключение в конструкторе VS2010. Вот с чем я работаю:

Text="{Binding Path=LearningOpportunities, StringFormat='Sharing & Learning Opportunitites:\{0\}'}"

Если я использую '&', он говорит мне: «Ссылки на объекты или последовательности, начинающиеся с амперсанда '&', должны заканчиваться точкой с запятой ';'». Если я использую & amp;, возникает исключение FormatException: «Индекс (отсчитываемый от нуля) должен быть больше или равен нулю и меньше размера списка аргументов». Некоторое время я занимался веб-разработкой вдали от WPF, поэтому чувствую себя немного ржавым. Как я могу заставить это работать?

Изменить: было много предположений о побеге, и, насколько я могу судить, все это неверно. Итак, чтобы избежать этого, вот что работает и не работает, исключив амперсанд из уравнения:

Работающие форматы:

StringFormat=Sharing and learning opportunitites:\{0\}
StringFormat='Sharing and learning opportunitites:\{0\}'
StringFormat={}Sharing and learning opportunitites:{0}
StringFormat='{}Sharing and learning opportunitites:{0}'
StringFormat=Sharing and learning opportunitites:{0}
StringFormat='Sharing and learning opportunitites:{0}'

Неработающие форматы:

StringFormat=Sharing and learning opportunitites:{}{0}
StringFormat=Sharing and learning opportunitites:{{0}}  (Outputs literal "{0}")

Подводя итог, вы можете убрать все фигурные скобки в строке, поместив открывающую и закрывающую фигурные скобки {} в начало строки, или вы можете экранировать отдельные фигурные скобки, используя обратную косую черту. Удивительно, но он по-прежнему работал без использования фигурных скобок, но расцветка синтаксиса в Visual Studio была довольно уродливой. Чтобы избежать некрасивой окраски синтаксиса, вы можете заключать строку формата в одинарные кавычки.

Таким образом, при остановленном экранировании проблема заключается в том, что добавление амперсанда к строке формата вызывает исключение, независимо от того, экранировано оно или нет. Единственная разница между экранированием и отсутствием экранирования - это другое исключение.


person xr280xr    schedule 22.03.2013    source источник
comment
Вы пробовали: stackoverflow.com/questions/1908761/   -  person N_A    schedule 22.03.2013
comment
Хм. Добавьте код в место, где вы пытаетесь выполнить вызов форматирования - есть еще кое-что.   -  person JerKimball    schedule 23.03.2013
comment
Отредактировано, чтобы показать, что я уже пробовал избежать амперсанда. @JerKimball, это код выше.   -  person xr280xr    schedule 23.03.2013
comment
Ах, понятно ... попробовать это? StringFormat = Панель Foo: {} {0}   -  person JerKimball    schedule 23.03.2013
comment
Интересно, что это так. Он вел себя так, как будто получит исключение, как только я наберу «&», но это работает. Спасибо! Если поставить как ответ, то отмечу.   -  person xr280xr    schedule 23.03.2013
comment
@ xr280xr Рад помочь - и не сдавайтесь, WPF немного сложно приходит из Интернета, но вы увидите много странных сходств между XAML и HTML ...   -  person JerKimball    schedule 23.03.2013
comment
@JerKimball Я в замешательстве. Ваше предложение появилось как Foo amp; раньше, и это то, что я сказал, сработало. Однако теперь я обнаружил, что он избавляется от ошибки, но в конечном итоге он выводит в моей строке. Так что это все еще не решено.   -  person xr280xr    schedule 25.03.2013
comment
@ xr280xr Grr ... Я ненавижу возиться с синтаксисом уценки ... Секунду, позвольте мне посмотреть, смогу ли я собрать полный пример, и я добавлю его к своему ответу.   -  person JerKimball    schedule 25.03.2013
comment
@ xr280xr Там, похоже, в тот раз все было опубликовано правильно - развеселить их?   -  person JerKimball    schedule 25.03.2013
comment
@JerKimball Я удивлен, что StringFormat=Foo & Bar: {}{0} работает на вас ... Вы используете это в реальной привязке, например {Binding SomeString, StringFormat=Foo & Bar: {}{0}}? Это не работает для меня. Я должен поставить {} перед всей строкой, а не только перед значением, как в моем ответе . Но я думаю, что разные синтаксисы могут работать с разными версиями WPF.   -  person Rachel    schedule 25.03.2013
comment
@Rachel Да, они все работают :) - FWIW, я использую WindowsBase / PresentationCore v4.0.30319 (О, Windows 7 тоже)   -  person JerKimball    schedule 25.03.2013
comment
@rachel - На случай, если редактор все еще возится с вещами, я также добавил ссылку pastebin.   -  person JerKimball    schedule 25.03.2013
comment
Глупые дизайнерские ошибки ... вот что, я предпочитаю эту, чтобы я мог ссылаться на нее в будущем ... на днях я посмотрю, есть ли способ как-нибудь обезьяно исправить неисправный код на дизайнере боковая сторона. Спасибо за интересный развлечение! ;)   -  person JerKimball    schedule 25.03.2013


Ответы (3)


EDITEDITEDIT:

Ага! Оказывается, это кровавый баг с дизайнерской поверхностью Сидра!

Доказательство:

Попробуйте эту последовательность строк XAML:

<StackPanel>
    <!-- should show '$YoMamma' -->
    <TextBlock Text="{Binding Path=Value, StringFormat=&#x24;{0}}"/>
    <!-- should show '%YoMamma' -->
    <TextBlock Text="{Binding Path=Value, StringFormat=&#x25;{0}}"/>
    <!-- should show '&YoMamma', but crashes the designer -->
    <!--<TextBlock Text="{Binding Path=Value, StringFormat=&#x26;{0}}"/>-->
    <!-- should show '"YoMamma', but crashes the designer -->
    <!--<TextBlock Text="{Binding Path=Value, StringFormat=&#x27;{0}}"/>-->
    <!-- should show '(YoMamma' -->
    <TextBlock Text="{Binding Path=Value, StringFormat=&#x28;{0}}"/>
    <!-- should show ')YoMamma' -->
    <TextBlock Text="{Binding Path=Value, StringFormat=&#x29;{0}}"/>

</StackPanel>

Я отправил отчет об ошибке для подключения, посмотрим, ответит ли кто-нибудь: https://connect.microsoft.com/VisualStudio/feedback/details/782059/cider-vs2010-designer-bug-with-binding-using-escaped-entity-in-stringformat

Остальная часть этого ответа является полу-спорной, хотя и потенциально полезной, поскольку «ошибка» лежит на дизайнере.

Здесь следует помнить, что XAML - это XML, поэтому вам необходимо соответствующим образом кодировать амперсанды:

&amp;

должно работать, а также:

&#38;

РЕДАКТИРОВАТЬ:

Ах, да - так что, как обсуждалось в комментариях, проблема заключалась не в амперсанде per se, а в "экранировании" замещающих маркеров в окружающих фигурных скобках Binding - чтобы исправить это, у вас есть три варианта:

РЕДАКТИРОВАТЬ 2: Ба, я думаю, что markdown может не понравиться мой пост (и я все равно ошибался в одном пункте) - давайте посмотрим, смогу ли я собрать полный пример:

На всякий случай вот и ссылка pastebin: http://pastebin.com/yfrpvxs1

Скажем, у нас есть такой объект контекста:

public class Foo : INotifyPropertyChanged
{
    private string _value;
    public string Value
    {
        get { return _value; }
        set { _value = value; FireNpc("Value"); }
    }
    private decimal _numberValue;
    public decimal NumberValue
    {
        get { return _numberValue; }
        set { _numberValue = value; FireNpc("NumberValue"); }
    }
    private DateTime _dateValue;
    public DateTime DateValue
    {
        get { return _dateValue; }
        set { _dateValue = value; FireNpc("DateValue"); }
    }
    public event PropertyChangedEventHandler PropertyChanged = delegate { };
    private void FireNpc(string name)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
}

И код окна:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new Foo()
            {
                Value = "YoMamma", 
                DateValue = DateTime.Now, 
                NumberValue = 3.14m
            };
    }
}

Давайте XAML!

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <!-- should show '#1:Foo & Bar:YoMamma' -->
        <TextBlock Text="{Binding Path=Value, StringFormat=#1:Foo &amp; Bar:{0}}"/>

        <!-- should show '#2:Foo & Bar:YoMamma' -->
        <TextBlock>
            <TextBlock.Text>
                <Binding Path="Value" StringFormat="#2:Foo &amp; Bar:{0}"/>
            </TextBlock.Text>
        </TextBlock>

        <!-- will actually show the '{' and '}', so 'Foo & Bar:{0}' -->
        <TextBlock Text="{Binding Path=Value, StringFormat=Foo &amp; Bar:{{0}}}"/>

        <!-- default 'custom' (there's a fun oxymoron) format - should be '$3.14' -->
        <TextBlock Text="{Binding Path=NumberValue, StringFormat=c}"/>

        <!-- custom 'custom' (bear with me) format -->
        <TextBlock Text="{Binding Path=DateValue, StringFormat=MM/dd/yyyy}"/>

        <!-- multi parameter formatting-->
        <TextBlock>
            <TextBlock.Text>
                <MultiBinding StringFormat="As of {2:MM/dd/yyyy}, {0} cost {1:c}">
                    <Binding Path="Value"/>
                    <Binding Path="NumberValue"/>
                    <Binding Path="DateValue"/>
                </MultiBinding>
            </TextBlock.Text>
        </TextBlock>
    </StackPanel>
</Window>

Теперь, воспользовавшись этим MultiBinding, мы можем сделать что-нибудь глупое - давайте добавим это в наш контекст:

    // Heh...don't actually do this, naturally...
    private string _ampersandValue;
    public string AmpersandValue
    {
        get { return _ampersandValue; }
        set { _ampersandValue = value; FireNpc("AmpersandValue"); }
    }


    this.DataContext = new Foo()
        {
            Value = "YoMamma", 
            DateValue = DateTime.Now, 
            NumberValue = 3.14m,
            AmpersandValue = "&"
        };

И добавьте этот XAML:

    <!-- And a crazy-person's method, using multi parameter formatting-->
    <TextBlock>
        <TextBlock.Text>
            <MultiBinding StringFormat="{}{0} {1} {0} = {0}">
                <Binding Path="Value"/>
                <Binding Path="AmpersandValue"/>
            </MultiBinding>
        </TextBlock.Text>
    </TextBlock>
person JerKimball    schedule 22.03.2013
comment
Редактор испортил мой пост. Пытался написать, что уже пробовал. - person xr280xr; 23.03.2013
comment
Спасибо за занимательный ответ. Но пробовали ли вы это? Амперсанд (первый символ) в первом и третьем текстовых блоках вызывает для меня исключение: индекс System.FormatException (на основе нуля) должен быть больше или равен нулю и меньше размера списка аргументов. - person xr280xr; 25.03.2013
comment
@ xr280xr - да, все это прямая копипаста из приложения wpf, которое я только что скинул; он отображается так, как ожидалось ... вы получили эту ошибку с этим кодом ?? - person JerKimball; 25.03.2013
comment
Ага, скопировал и вставил в тестовый проект. Использование VS 2010 и .NET Framework 4 - person xr280xr; 25.03.2013
comment
@ xr280xr О, тогда все становится интереснее ... как насчет той ссылки на pastebin, которую я добавил? - person JerKimball; 25.03.2013
comment
Тот же результат. И в моем реальном, и в тестовом проекте, когда я набираю символ амперсанда в строку формата, он взрывается. Единственный способ, которым я мог иметь символ '&' в строке формата без его взрыва, - это использовать amp;, что приводит к отображению строки. Не очень полезно, но, возможно, подсказка. Очень странно, что у тебя работает, а не у меня. Это было то, что я изначально ожидал, прежде чем опубликовать этот вопрос. - person xr280xr; 25.03.2013
comment
@ xr280xr Ой, подождите - дизайнер взорвется, как только вы это напечатаете? - person JerKimball; 25.03.2013
comment
давайте продолжим обсуждение в чате - person JerKimball; 25.03.2013
comment
Итак, итоги: либо используйте встроенный синтаксис за счет взрыва дизайнера (но он все равно будет работать во время выполнения), либо используйте полный синтаксис привязки, чтобы сохранить поддержку дизайнера. Главный реквизит для JerKimball! - person xr280xr; 25.03.2013
comment
@ xr280xr Ха, нашел одну вещь, которая может сработать ... альтернативный символ амперсанда: <TextBlock Text="{Binding Path=Value, StringFormat=A &#xff06; B:{0}}"/> - person JerKimball; 25.03.2013
comment
Для символа Юникода амперсанда полной ширины это хорошо. Поскольку технически это другой символ, вы также можете поместить его прямо в разметку, не экранируя его. Похоже, что между разными шрифтами могут возникнуть проблемы. - person xr280xr; 26.03.2013

Вам нужно использовать &amp; для амперсанда и удалить \, которые действуют как escape-символы. У вас также есть лишние ' символы, которые не требуются. Попробуйте следующее:

Text="{Binding Path=LearningOpportunities, StringFormat=Sharing &amp; Learning Opportunitites:{0}}"
person Reed Copsey    schedule 22.03.2013
comment
@ xr280xr Отредактировано - проблема заключалась в том, что &amp; не использовался, а в ... - person Reed Copsey; 23.03.2013
comment
Я думаю, что Рид прав: я думаю, что вас портят скобки, а не амперсанд; проверьте комментарий, который я добавил к op - person JerKimball; 23.03.2013
comment
Кстати, Рид: основная причина на самом деле ошибка дизайнера; весело, весело, весело ... и кое-что, что нужно отметить в справочнике вашего мозга;) - person JerKimball; 26.03.2013

Каждый раз, когда я хочу использовать StringFormat в привязке, и мой формат содержит дополнительный текст или пробелы, я помещаю дополнительный набор фигурных скобок спереди, например:

StringFormat={}Sharing and learning opportunitites:{0}

Я знаю, что видел в Интернете ссылки с использованием других методов, но все они в то или иное время подводили меня. Я думаю, что разные версии WPF поддерживают разные StringFormat синтаксисы, поэтому, в зависимости от того, какую версию вы используете, может работать и другой синтаксис, однако приведенный выше - единственный, который я считаю достаточно универсальным.

Кроме того, вы захотите использовать &amp; для экранирования символа &.

StringFormat={}Sharing &amp; learning opportunitites:{0}
person Rachel    schedule 25.03.2013