WPF StringFormat en el contenido de la etiqueta

77

Quiero formatear mi enlace de cadena como Amount is Xdónde Xestá una propiedad vinculada a una etiqueta.

He visto muchos ejemplos, pero lo siguiente no funciona:

<Label Content="{Binding Path=MaxLevelofInvestment, 
   StringFormat='Amount is {0}'}" />

También probé estas combinaciones:

StringFormat=Amount is {0}
StringFormat='Amount is {}{0}'
StringFormat='Amount is \{0\}'

Incluso intenté cambiar el tipo de datos de la propiedad de enlace a int, stringy double. Nada parece funcionar. Este es un caso de uso muy común, pero no parece ser compatible.

Todo importa
fuente

Respuestas:

205

La razón por la que esto no funciona es que la Label.Contentpropiedad es de tipo Objecty Binding.StringFormatsolo se usa cuando se vincula a una propiedad de tipo String.

Lo que esta pasando es:

  1. Se Bindingcoloca en caja su MaxLevelOfInvestmentvalor y se almacena la Label.Contentpropiedad como un valor decimal en caja.
  2. El control Etiqueta tiene una plantilla que incluye un ContentPresenter.
  3. Como ContentTemplateno está establecido, ContentPresenterbusca un DataTemplatedefinido para el Decimaltipo. Cuando no encuentra ninguno, utiliza una plantilla predeterminada.
  4. La plantilla predeterminada utilizada por las ContentPresentercadenas de presenta mediante el uso de la ContentStringFormatpropiedad de la etiqueta .

Son posibles dos soluciones:

  • Utilice Label.ContentStringFormat en lugar de Binding.StringFormat, o
  • Utilice una propiedad String como TextBlock.Text en lugar de Label.Content

A continuación, se explica cómo utilizar Label.ContentStringFormat:

<Label Content="{Binding Path=MaxLevelofInvestment}" ContentStringFormat="Amount is {0}" />

A continuación se explica cómo usar un TextBlock:

<TextBlock Text="{Binding Path=MaxLevelofInvestment, StringFormat='Amount is {0}'}" />

Nota: Para simplificar he omitido un detalle de la explicación anterior: La ContentPresenterrealidad utiliza sus propios Templatey StringFormatpropiedades, pero durante la carga de estos son automáticamente la plantilla unida a los ContentTemplatey las ContentStringFormatpropiedades de la Label, por lo que parece como si la ContentPresenterrealidad está utilizando las Labelpropiedades 's .

Ray Burns
fuente
gracias por la explicación detallada, ahora tiene sentido. hasta el equipo de WPF para hacer esto ordenado para el futuro.
Everything Matters
Me gusta tu respuesta, ¿sabrías cómo usar 2 parámetros en lugar de solo 1? Realmente luchando aquí (como TextBlock stringFormat puede manejar múltiples cuando se usan activadores, etc.).
EricG
¿Por qué en este caso necesita poner Path = delante de su enlace? normalmente podría hacerlo Content="{Binding MaxLevelofInvestment}"y funciona bien ...
MistaGoustan
6
Para la posteridad: si comienza un ContentStringFormat con a {0}, no olvide poner {}antes. Así que ContentStringFormat="{}{0} some text here"
hazlo
7

Haz un universal StringFormatConverter : IValueConverter. Pase su cadena de formato como ConverterParameter.

Label Content="{Binding Amount, Converter={...myConverter}, ConverterParameter='Amount is {0}'"

Además, asegúrese StringFormatMultiConverter : IMultiValueConvertercuando se necesita más de un objeto en la cadena de formato, por ejemplo, Completed {0} tasks out of {1}.

Michael Agroskin
fuente
Me gusta esto. Puedo ver el valor de usar tanto el XAMLenfoque puro como el convertidor de valor.
IAbstract
4

Acabo de verificar y por alguna razón no funciona con la etiqueta, probablemente porque usa un ContentPresenter para la propiedad Content internamente. Puedes usar TextBlock en su lugar y eso funcionará. También puede colocar el extracto de TextBlock a continuación en el contenido de una etiqueta si necesita heredar el estilo, el comportamiento, etc.

<TextBlock Text="{Binding Path=MaxLevelofInvestment, StringFormat='Amount is \{0\}'} />
Chico
fuente
1

Intenta usar un convertidor ...

<myconverters:MyConverter x:Key="MyConverter"/>


<Label Content="{Binding Path=MaxLevelofInvestment, Converter={StaticResource MyConverter"} />


public class MyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return String.Format("Amount is {0}", value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }
}
Gabe
fuente
4
Es una exageración. Explico la causa del problema y presento dos soluciones simples en mi respuesta.
Ray Burns
Estoy de acuerdo en que esto oculta el uso, recientemente heredé un proyecto en el que se adoptó este enfoque y preferiría que los desarrolladores usen la compilación en StringFormat que la suya propia.
Fermín