XAML 根据用户选择在WPF中显示数字的小数位

xghobddn  于 2023-09-28  发布在  其他
关注(0)|答案(2)|浏览(211)

我想在WPF窗口中显示一些double类型。应允许用户选择应显示的小数位数。
我想直接在视图(XAML)中解决这个问题,而不需要在代码后面格式化数字。我尝试使用 StringFormatMultiBinding 显示具有选定小数位数的绑定数字:
MainWindow.xaml:

<Window x:Class="WpfApp1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    Width="400"  Height="100">

<StackPanel Orientation="Horizontal" Height="30">

    <TextBlock  Margin="5" >Precision:</TextBlock>
    
    <ComboBox x:Name="cbPrecision" 
                Margin="5" 
                MinWidth="80"
                ItemsSource="{Binding Path=DecimalPlaces}" 
                DisplayMemberPath="Value" 
                SelectedValuePath="Key"/>

    <TextBlock Margin="5" >
        <TextBlock.Text>
            <MultiBinding StringFormat="Number: {0:N{1}}">
                <Binding Path="SomeNumber"/>
                <Binding Path="SelectedValue" ElementName="cbPrecision"/>
            </MultiBinding>
        </TextBlock.Text>
    </TextBlock>

</StackPanel>

MainWindow.xaml.cs:

using System.Collections.Generic;
using System.Windows;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {

        public MainWindow()
        {
            InitializeComponent();
        }

        public Dictionary<int, double> DecimalPlaces { get; } = new() {
            { 0, 1 },
            { 1, 0.1 },
            { 2, 0.01 },
            { 3, 0.001 }
        };

        public double SomeNumber { get; set; } = 123.45678;
    }
}

因此根本不显示TextBox:

预期结果:

观察:

“嵌套”字符串格式一定有问题

<MultiBinding StringFormat="Number: {0:N{1}}">

因为将包含StringFormat的代码行更改为

<MultiBinding StringFormat="Number: {0:N4}-DecimalPlaces: {1}">

正确显示文本框中的值:

eqqqjvef

eqqqjvef1#

首先,将TextBlock替换为Label,它具有用于绑定的ContentStringFormat属性。
然后,定义一个实现INotifyPropertyChanged接口的类。
具体实现如下:

// in Window_Loaded
panel.DataContext = new PanelModel();

class PanelModel : INotifyPropertyChanged
{
    public Dictionary<string, double> DecimalPlaces { get; } = new() {
        { "N0", 1 },
        { "N1", 0.1 },
        { "N2", 0.01 },
        { "N3", 0.001 },
        { "N4", 0.0001 }
    };

    string _ContentFormat = "N0";
    double _SomeNumber = 123.45678;

    public string ContentFormat {
        get => _ContentFormat;
        set
        {
            if (value != _ContentFormat)
            {
                _ContentFormat = value;
                OnPropertyChanged(nameof(ContentFormat));
                OnPropertyChanged(nameof(SomeNumber));
            }
        }
    }

    public double SomeNumber
    {
        get => _SomeNumber;
        set
        {
            if (value != _SomeNumber)
            {
                _SomeNumber = value;
                OnPropertyChanged(nameof(SomeNumber));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

我尝试将comboBox1.SelectedValue绑定到ContentStringFormat,但不起作用。
因此,我使用了INotifyPropertyChanged接口,并在ContentFormat更改时触发了SomeNumberChanged 通知。

<StackPanel x:Name="panel" Orientation="Horizontal">

    <Label Content="Precision: " />

    <ComboBox x:Name="comboBox1"
                ItemsSource="{Binding Path=DecimalPlaces}"
                DisplayMemberPath="Value"
                SelectedValuePath="Key"
                SelectedValue="{Binding Path=ContentFormat}"
                VerticalContentAlignment="Center"
                Width="120"/>

    <TextBox Text="{Binding Path=SomeNumber, UpdateSourceTrigger=PropertyChanged}"
             Width="120"
             Margin="15,0"/>

    <Label x:Name="labelSomeNumber"
            Content="{Binding Path=SomeNumber}"
            ContentStringFormat="{Binding Path=ContentFormat}" />

</StackPanel>
fdx2calv

fdx2calv2#

根据克莱门斯的评论,我创建了一个转换器。完整的解决方案:

  • MainWindow.xaml:*
<Window x:Class="WpfApp1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    xmlns:local="clr-namespace:WpfApp1"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    Width="400"  Height="100">

<StackPanel Orientation="Horizontal" Height="30">

    <TextBlock  Margin="5" >Precision:</TextBlock>
    
    <ComboBox x:Name="cbPrecision" 
                Margin="5" 
                MinWidth="80"
                ItemsSource="{Binding Path=DecimalPlaces}" 
                DisplayMemberPath="Value" 
                SelectedValuePath="Key"/>

    <TextBlock Margin="5" >
        <TextBlock.Text>
            <MultiBinding>
                <MultiBinding.Converter>
                    <local:DecimalPlacesConverter />
                </MultiBinding.Converter>
                <Binding Path="SomeNumber"/>
                <Binding Path="SelectedValue" ElementName="cbPrecision"/>
            </MultiBinding>
        </TextBlock.Text>
    </TextBlock> 
</StackPanel>
  • MainWindow.xaml.cs:*
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
    public Dictionary<int, double> DecimalPlaces { get; } = new() {
        { 0, 1 },
        { 1, 0.1 },
        { 2, 0.01 },
        { 3, 0.001 }
    };
    public double SomeNumber { get; set; } = 123.45678;
}
  • DecimalPlacesConverter.cs:*
public class DecimalPlacesConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        try
        {
            return Math.Round((double)values[0], (int)values[1]).ToString("N" + values[1]);
        }
        catch (Exception)
        {
            return double.NaN;
        }
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

相关问题