Làm thế nào để định dạng số vị trí thập phân trong wpf bằng cách sử dụng kiểu / mẫu?


94

Tôi đang viết một chương trình WPF và tôi đang cố gắng tìm ra cách để định dạng dữ liệu trong TextBox thông qua một số phương pháp có thể lặp lại như kiểu hoặc mẫu. Tôi có rất nhiều TextBox (chính xác là 95) và mỗi cái được liên kết với dữ liệu số của riêng nó, mỗi cái có thể có độ phân giải riêng được xác định. Ví dụ: nếu dữ liệu là 99.123 với độ phân giải là 2 thì nó sẽ hiển thị 99.12. Tương tự, giá trị dữ liệu là 99 và độ phân giải 3 sẽ được hiển thị là 99.000 (không phải 99). Có cách nào để làm việc này không?

Chỉnh sửa: Tôi nên làm rõ, có 95 TextBox trên màn hình hiện tại mà tôi đang làm việc, nhưng tôi muốn mọi TextBox trên khắp các màn hình khác nhau trong chương trình của mình hiển thị đúng số vị trí thập phân. Bây giờ tôi nghĩ về nó, một số trong số này là TextBox (như màn hình tôi đang làm việc bây giờ) và một số là DataGrids hoặc ListViews, nhưng nếu tôi có thể tìm ra cách làm cho nó hoạt động cho TextBoxes, tôi chắc chắn tôi có thể tìm ra nó cũng cho các điều khiển khác.

Không có nhiều mã để chia sẻ trong trường hợp này nhưng tôi sẽ cố gắng làm cho nó rõ ràng hơn:

Tôi có Mô hình dạng xem chứa các thuộc tính sau (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

và trong XAML tôi có:

<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 (giải pháp của tôi): Hóa ra là sau khi rời khỏi máy tính một lúc, tôi quay lại và thấy một câu trả lời đơn giản đang nhìn chằm chằm vào mặt tôi. Định dạng dữ liệu trong mô hình xem!

    Public ReadOnly Property Value As String
        Get
            Return (Strings.FormatNumber(Math.Round(_signal.DisplayValue, _signal.DisplayResolution), _signal.DisplayResolution))
        End Get
    End Property

1
sử dụng a IValueConverter? Chuyển giá trị thực và độ phân giải cho bộ chuyển đổi và để nó tự làm tròn cho bạn. Thật khó để đề xuất một StringFormatmà không biết chính xác 95 TextBox's này được tạo ra như thế nào .
Viv

Đăng mã hiện tại và XAML. Nếu không thì đó là tất cả những suy đoán và phỏng đoán vô ích.
Federico Berasategui

Tôi đã thêm một số thông tin vào câu hỏi hy vọng sẽ làm cho nó rõ ràng hơn.
AXG1010

Câu trả lời:


196

Bạn nên sử dụng StringFormattrên Binding. Bạn có thể sử dụng định dạng chuỗi tiêu chuẩn hoặc định dạng chuỗi tùy chỉnh :

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

Lưu ý rằng StringFormatchỉ hoạt động khi thuộc tính đích có kiểu chuỗi. Nếu bạn đang cố gắng đặt một cái gì đó như thuộc Contenttính ( typeof(object)), bạn sẽ cần sử dụng một tùy chỉnh StringFormatConverter( như ở đây ) và chuyển chuỗi định dạng của bạn dưới dạng ConverterParameter.

Chỉnh sửa cho câu hỏi cập nhật

Vì vậy, nếu bạn ViewModelxác định độ chính xác, tôi khuyên bạn nên làm điều này với tư cách là một MultiBindingvà tạo của riêng bạn IMultiValueConverter. Điều này khá khó chịu trong thực tế, để đi từ một ràng buộc đơn giản đến một ràng buộc cần được mở rộng thành a MultiBinding, nhưng nếu độ chính xác không được biết tại thời điểm biên dịch, đây là tất cả những gì bạn có thể làm. Bạn IMultiValueConvertersẽ cần lấy giá trị và độ chính xác và xuất ra chuỗi được định dạng. Bạn có thể làm điều này bằng cách sử dụng String.Format.

Tuy nhiên, đối với những thứ như a ContentControl, bạn có thể dễ dàng làm điều này hơn nhiều với Style:

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

Bất kỳ điều khiển nào để lộ a ContentStringFormatđều có thể được sử dụng như thế này. Thật không may, TextBoxkhông có bất cứ điều gì như vậy.


6
Ví dụ với StringFormat được đặt thành #,#.00không biên dịch - dấu phẩy được hiểu là dấu phân cách cho các thuộc tính trong Bindingphần mở rộng đánh dấu.
Gigi

@Gigi, bạn nói đúng, nhưng bạn có thể dễ dàng sử dụng nó như vậy: StringFormat={}{0:#,#.00}. Tôi sẽ cập nhật câu trả lời để hoạt động chính xác.
Abe Heidebrecht

'StringFormat = N {0}' hoạt động tốt. Đối với độ chính xác là 2, tôi muốn hiển thị hai số thập phân, ngoại trừ '10 .00 ', trong trường hợp đó tôi muốn hiển thị' 10 '. Có cách nào để làm điều này khi ràng buộc với độ chính xác không? Có vẻ như tôi sẽ phải sử dụng một bộ chuyển đổi.
Gordon Slysz

Tôi không nghĩ có cách nào để thay đổi số thập phân được trình bày bằng các định dạng chuỗi .NET, vì vậy có lẽ bạn nên viết một trình chuyển đổi.
Abe Heidebrecht

Bạn có thể giải thích tại sao sử dụng hai từ chỉ định 0: #, #. 00, không chỉ một trong số chúng là đủ?
Lei Yang

7

Câu trả lời được chấp nhận không hiển thị 0 ở vị trí số nguyên khi đưa ra đầu vào như 0,299. Nó hiển thị .3 trong giao diện người dùng WPF. Vì vậy, đề xuất của tôi là sử dụng định dạng chuỗi sau

<TextBox Text="{Binding Value,  StringFormat={}{0:#,0.0}}" 

Xin chào, giải pháp của bạn ổn nhưng tôi muốn sử dụng từ khóa N1 (2,3 ...) vì nó tránh được lỗi đánh máy và ít nhất bạn chắc chắn nó sẽ được hiển thị như thế nào. Nhưng thực sự gợi ý thứ hai không hiển thị giá trị 0 if <0 như bạn đề cập.
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;
        }
    }

9
Một số giải thích sẽ cải thiện đáng kể chất lượng câu trả lời của bạn.
mrun
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.