WPF StringFormat für Etiketteninhalte

76

Ich möchte meinen String formatiert werden verbindlich, Amount is Xwo Xan eine Markierung gebunden ist eine Eigenschaft.

Ich habe viele Beispiele gesehen, aber das Folgende funktioniert nicht:

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

Ich habe auch diese Kombinationen ausprobiert:

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

Ich habe sogar versucht die Bindungseigenschaft des Datentyps zu ändern int, stringund double. Nichts scheint zu funktionieren. Dies ist ein sehr häufiger Anwendungsfall, scheint jedoch nicht unterstützt zu werden.

Alles ist wichtig
quelle

Antworten:

201

Der Grund, warum dies nicht funktioniert, ist, dass die Label.ContentEigenschaft vom Typ Objectist und Binding.StringFormatnur beim Binden an eine Eigenschaft vom Typ verwendet wird String.

Was passiert ist:

  1. Das Bindingboxt Ihren MaxLevelOfInvestmentWert und speichert die Label.ContentEigenschaft als dezimalen Boxwert.
  2. Das Label-Steuerelement verfügt über eine Vorlage, die a enthält ContentPresenter.
  3. Da ContentTemplatenicht gesetzt ist, ContentPresentersucht nach einem DataTemplatefür den DecimalTyp definierten . Wenn keine gefunden wird, wird eine Standardvorlage verwendet.
  4. Die Standardvorlage, die von den ContentPresenterPresent-Zeichenfolgen mithilfe der ContentStringFormatEigenschaft des Labels verwendet wird .

Zwei Lösungen sind möglich:

  • Verwenden Sie Label.ContentStringFormat anstelle von Binding.StringFormat oder
  • Verwenden Sie eine String-Eigenschaft wie TextBlock.Text anstelle von Label.Content

So verwenden Sie Label.ContentStringFormat:

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

So verwenden Sie einen TextBlock:

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

Hinweis: Der Einfachheit halber habe ich in der obigen Erklärung ein Detail weggelassen: Das verwendet ContentPresentertatsächlich seine eigenen Templateund StringFormatEigenschaften, aber während des Ladens werden diese automatisch an die ContentTemplateund ContentStringFormatEigenschaften des und gebunden Label, sodass es so aussieht, als ob das ContentPresentertatsächlich die LabelEigenschaften des verwendet .

Ray Burns
quelle
danke für die ausführliche erklärung, jetzt macht es sinn. bis zum WPF-Team, um dies für die Zukunft ordentlich zu machen.
Alles ist
Ich mag Ihre Antwort, würden Sie wissen, wie man 2 Parameter anstelle von nur 1 verwendet? Wirklich Probleme hier (wie TextBlock stringFormat kann mehrere verarbeiten, wenn Trigger usw. verwendet werden).
EricG
Warum müssen Sie in diesem Fall Path = vor Ihre Bindung stellen? Normalerweise könnte ich Content="{Binding MaxLevelofInvestment}"es einfach tun und es funktioniert
einwandfrei
4
Für die Nachwelt: Wenn Sie ein ContentStringFormat mit einem starten {0}, vergessen Sie nicht, es {}davor zu setzen . Also mach esContentStringFormat="{}{0} some text here"
jep
7

Machen Sie eine universelle StringFormatConverter : IValueConverter. Übergeben Sie Ihre Formatzeichenfolge als ConverterParameter.

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

Machen StringFormatMultiConverter : IMultiValueConverterSie auch, wenn Sie beispielsweise mehr als ein Objekt im Format string benötigen Completed {0} tasks out of {1}.

Michael Agroskin
quelle
Ich mag das. Ich kann den Wert der Verwendung sowohl des reinen XAMLAnsatzes als auch des Wertekonverters erkennen.
IAbstract
4

Ich habe es gerade überprüft und aus irgendeinem Grund funktioniert es nicht mit dem Label, wahrscheinlich weil es intern einen ContentPresenter für die Content-Eigenschaft verwendet. Sie können stattdessen einen TextBlock verwenden, und das wird funktionieren. Sie können den folgenden TextBlock-Auszug auch in den Inhalt eines Labels einfügen, wenn Sie Stil, Verhalten usw. erben müssen.

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

Versuchen Sie es mit einem Konverter ....

<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
quelle
4
Es ist übertrieben. Ich erkläre die Ursache des Problems und präsentiere in meiner Antwort zwei einfache Lösungen.
Ray Burns
Ich bin damit einverstanden, dass dies die Verwendung verbirgt. Ich habe kürzlich ein Projekt geerbt, in dem dieser Ansatz gewählt wurde, und würde Entwicklern den Build in StringFormat vorziehen, anstatt ihre eigenen zu rollen.
Fermin