Wie formatiere ich die Anzahl der Dezimalstellen in wpf mit style / template?

87

Ich schreibe ein WPF-Programm und versuche herauszufinden, wie Daten in einer TextBox mithilfe einer wiederholbaren Methode wie einem Stil oder einer Vorlage formatiert werden können. Ich habe viele TextBoxen (95 um genau zu sein) und jede ist an ihre eigenen numerischen Daten gebunden, für die jeweils eine eigene Auflösung definiert werden kann. Wenn die Daten beispielsweise 99,123 mit einer Auflösung von 2 sind, sollte sie 99,12 anzeigen. Ebenso sollte ein Datenwert von 99 und Auflösung 3 als 99.000 (nicht 99) angezeigt werden. Gibt es eine Möglichkeit, dies zu tun?

Bearbeiten: Ich sollte klarstellen, dass sich auf dem aktuellen Bildschirm, an dem ich arbeite, 95 Textfelder befinden, aber ich möchte, dass jedes Textfeld auf den verschiedenen Bildschirmen in meinem Programm die richtige Anzahl von Dezimalstellen anzeigt. Nun, da ich darüber nachdenke, sind einige davon TextBoxen (wie der Bildschirm, an dem ich gerade arbeite) und andere DataGrids oder ListViews, aber wenn ich herausfinden kann, wie es für TextBoxen funktioniert, kann ich es sicher herausfinden es auch für die anderen Kontrollen.

In diesem Fall gibt es nicht viel Code zum Teilen, aber ich werde versuchen, es klarer zu machen:

Ich habe ein Ansichtsmodell, das die folgenden Eigenschaften enthält (vb.net):

    Public ReadOnly Property Resolution As Integer
        Get
            Return _signal.DisplayResolution
        End Get
    End Property

    Public ReadOnly Property Value As Single
        Get
            Return Math.Round(_signal.DisplayValue, Resolution)
        End Get
    End Property

und in der XAML habe ich:

<UserControl.Resources>
    <vm:SignalViewModel x:Key="Signal" SignalPath="SomeSignal"/>
</UserControl.Resources>
<TextBox Grid.Column="3" IsEnabled="False" Text="{Binding Path=Value, Source={StaticResource Signal}, Mode=OneWay}" />

EDIT2 (meine Lösung): Es stellte sich heraus, dass ich, nachdem ich eine Weile vom Computer weggegangen war , zurückkam, um eine einfache Antwort zu finden, die mich ins Gesicht starrte. Formatieren Sie die Daten im Ansichtsmodell!

    Public ReadOnly Property Value As String
        Get
            Return (Strings.FormatNumber(Math.Round(_signal.DisplayValue, _signal.DisplayResolution), _signal.DisplayResolution))
        End Get
    End Property
AXG1010
quelle
1
benutze ein IValueConverter? Übergeben Sie den tatsächlichen Wert und die Auflösung an den Konverter und lassen Sie ihn für sich selbst aufrunden. Es ist schwer, eine vorzuschlagen, StringFormatohne zu wissen, wie genau diese 95er TextBoxerzeugt werden.
Viv
Veröffentlichen Sie den aktuellen Code und XAML. Ansonsten sind es nur Spekulationen und nicht hilfreiche Vermutungen.
Federico Berasategui
Ich habe der Frage weitere Informationen hinzugefügt, die sie hoffentlich klarer machen sollen.
AXG1010

Antworten:

187

Sie sollten die StringFormatauf der verwenden Binding. Sie können entweder Standardzeichenfolgenformate oder benutzerdefinierte Zeichenfolgenformate verwenden :

<TextBox Text="{Binding Value, StringFormat=N2}" />
<TextBox Text="{Binding Value, StringFormat={}{0:#,#.00}}" />

Beachten Sie, dass dies StringFormatnur funktioniert, wenn die Zieleigenschaft vom Typ Zeichenfolge ist. Wenn Sie versuchen, so etwas wie eine ContentEigenschaft ( typeof(object)) festzulegen, müssen Sie eine benutzerdefinierte StringFormatConverter( wie hier ) verwenden und Ihre Formatzeichenfolge als übergeben ConverterParameter.

Für aktualisierte Frage bearbeiten

Wenn Sie also ViewModeldie Genauigkeit definieren, würde ich empfehlen, dies als zu tun MultiBindingund Ihre eigene zu erstellen IMultiValueConverter. In der Praxis ist dies ziemlich ärgerlich, von einer einfachen Bindung zu einer zu wechseln, die zu einer erweitert werden MultiBindingmuss. Wenn die Genauigkeit beim Kompilieren jedoch nicht bekannt ist, ist dies so ziemlich alles, was Sie tun können. Sie IMultiValueConvertermüssten den Wert und die Genauigkeit übernehmen und die formatierte Zeichenfolge ausgeben. Sie könnten dies mit tun String.Format.

Für Dinge wie a ContentControlkönnen Sie dies jedoch viel einfacher tun mit Style:

<Style TargetType="{x:Type ContentControl}">
    <Setter Property="ContentStringFormat" 
            Value="{Binding Resolution, StringFormat=N{0}}" />
</Style>

Jedes Steuerelement, das a verfügbar macht, ContentStringFormatkann wie folgt verwendet werden. Hat TextBoxso etwas leider nicht.

Abe Heidebrecht
quelle
5
Das Beispiel mit StringFormat #,#.00wird nicht kompiliert. Das Komma wird als Trennzeichen für Attribute in der BindingMarkup-Erweiterung interpretiert .
Gigi
@ Gigi, du hast recht, aber du kannst es einfach so benutzen : StringFormat={}{0:#,#.00}. Ich werde die Antwort aktualisieren, damit sie richtig funktioniert.
Abe Heidebrecht
Das 'StringFormat = N {0}' funktioniert hervorragend. Für eine Genauigkeit von 2 möchte ich, dass zwei Dezimalstellen angezeigt werden, mit Ausnahme von '10 .00 '. In diesem Fall möchte ich' 10 'anzeigen. Gibt es eine Möglichkeit, dies zu tun, wenn Sie an die Präzision binden? Scheint, als müsste ich einen Konverter verwenden.
Gordon Slysz
Ich glaube nicht, dass es eine Möglichkeit gibt, die mit .NET-Zeichenfolgenformaten dargestellten Dezimalstellen zu ändern. Daher ist es wahrscheinlich besser, einen Konverter zu schreiben.
Abe Heidebrecht
Können Sie erklären, warum die Verwendung von zwei Bezeichnern 0: #, #. 00, nicht nur einer von ihnen ausreicht?
Lei Yang
7

Die akzeptierte Antwort zeigt bei einer Eingabe wie 0,299 keine 0 an einer ganzzahligen Stelle. Es zeigt .3 in der WPF-Benutzeroberfläche. Also mein Vorschlag, folgendes String-Format zu verwenden

<TextBox Text="{Binding Value,  StringFormat={}{0:#,0.0}}" 
Manish Dubey
quelle
Hallo, Ihre Lösung ist in Ordnung, aber ich möchte lieber das Schlüsselwort N1 (2,3 ...) verwenden, da es Tippfehler vermeidet und Sie zumindest sicher sind, wie es angezeigt wird. In der Tat zeigt der zweite Vorschlag nicht die 0, wenn der Wert <0 ist, wie Sie erwähnen.
Kevin VDF
-2
    void NumericTextBoxInput(object sender, TextCompositionEventArgs e)
    {
        TextBox txt = (TextBox)sender;
        var regex = new Regex(@"^[0-9]*(?:\.[0-9]{0,1})?$");
        string str = txt.Text + e.Text.ToString();
        int cntPrc = 0;
        if (str.Contains('.'))
        {
            string[] tokens = str.Split('.');
            if (tokens.Count() > 0)
            {
                string result = tokens[1];
                char[] prc = result.ToCharArray();
                cntPrc = prc.Count();
            }
        }
        if (regex.IsMatch(e.Text) && !(e.Text == "." && ((TextBox)sender).Text.Contains(e.Text)) && (cntPrc < 3))
        {
            e.Handled = false;
        }
        else
        {
            e.Handled = true;
        }
    }
Monali Pawar
quelle
8
Einige Erklärungen würden die Qualität Ihrer Antwort erheblich verbessern.
Mrun