首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >WPF中推荐的DisplayFormatAttribute替代方案是什么?

WPF中推荐的DisplayFormatAttribute替代方案是什么?
EN

Stack Overflow用户
提问于 2017-08-11 19:07:16
回答 1查看 563关注 0票数 1

所以我找到了DisplayFormatAttribute类(我想这仅仅是用于Web开发?)。这将真正改善我的项目的可维护性,因为我有许多十进制属性,其小数位数似乎一次又一次地改变(客户需求与我的“聪明”想法混合在一起)。

基本上,我会有这样的财产:

代码语言:javascript
运行
复制
[DisplayFormat(DataFormatString = "{0:n4} %")]
public decimal Nh3 {get; set;}

DisplayFormatAttribute所示,需要在当前用户区域设置中显示四个小数,后面跟着一个%。

在XAML中,我会有这样的东西

代码语言:javascript
运行
复制
<TextBlock Text="{Binding Nh3}"/>

但是对于像0.123456这样的值,它将显示0.123456,对于像0.12这样的值,它将显示0.12。我需要它分别显示0.1235 %0.1200 %

对于特定的TextBlock,可以通过

代码语言:javascript
运行
复制
<TextBlock Text="{Binding Nh3, StringFormat={}{0:n4} %"/>

但正如我所提到的,这是重复和容易出错的.

我看到有人用类似的东西

代码语言:javascript
运行
复制
<TextBlock Text="{Binding Nh3, StringFormat={StaticResource Nh3Format} %"/>

但我发现这是相当复杂的(与Nh3属性上的属性相比)。但我希望有人能帮我更好地解决这个问题。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-08-13 04:41:25

您可以定义自己的DisplayFormatAttribute自定义标记扩展来自动为您创建这些绑定。

代码语言:javascript
运行
复制
///Custom attribute
[AttributeUsageAttribute(AttributeTargets.Property, AllowMultiple = false)]
public class DisplayFormatAttribute : Attribute
{
    public string DataFormatString { get; set; }
}

///Custom markup extension
[ContentProperty("ResourceKey")]
[MarkupExtensionReturnType(typeof(object))]
public class FormattedBindingExtension : MarkupExtension
{
    public FormattedBindingExtension()
    {
    }

    public FormattedBindingExtension(PropertyPath path)
    {
        Path = path;
    }

    public IValueConverter Converter { get; set; }
    public object ConverterParamter { get; set; }

    [ConstructorArgument("path")]
    public PropertyPath Path { get; set; }

    [TypeConverter(typeof(CultureInfoIetfLanguageTagConverter))]
    public CultureInfo ConverterCulture { get; set; }

    private DependencyProperty _bindingTargetProperty;
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var valueProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
        if (valueProvider != null)
        {
            var bindingTarget = valueProvider.TargetObject as DependencyObject;
            var bindingTargetProperty = valueProvider.TargetProperty as DependencyProperty;
            if (bindingTargetProperty == null || bindingTarget == null || Path == null)
            {
                throw new NotSupportedException(string.Format(
                    "The property '{0}' on target '{1}' is not valid for a FormattedBinding. The FormattedBinding target must be a DependencyObject, "
                    + "and the target property must be a DependencyProperty, and a Path must be specified.",
                    valueProvider.TargetProperty,
                    valueProvider.TargetObject));
            }

            // Add support so that the datacontext change causes an immediate commit with format
            var frameworkElement = bindingTarget as FrameworkElement;
            if (frameworkElement != null)
            {
                frameworkElement.DataContextChanged += FrameworkElement_DataContextChanged;
            }

            _bindingTargetProperty = bindingTargetProperty;
            FrameworkElement_DataContextChanged(frameworkElement, new DependencyPropertyChangedEventArgs());

            // Return the current value of the binding (since it will have been evaluated because of the binding above)
            return bindingTarget.GetValue(bindingTargetProperty);
        }
        return null;
    }

    private void FrameworkElement_DataContextChanged(object sender, DependencyPropertyChangedEventArgs ignored)
    {
        var element = sender as FrameworkElement;
        if (element == null || element.DataContext == null)
            return;

        var propertyName = Path.Path;
        if (propertyName == null)
            return;

        var source = element.DataContext;
        var type = source.GetType();

        var property = type.GetProperty(propertyName);
        var format = property.GetCustomAttribute<DisplayFormatAttribute>()?.DataFormatString;
        Binding binding = GetBinding(format);

        // Apply and evaluate the binding
        var bindingExpression = BindingOperations.SetBinding(element, _bindingTargetProperty, binding);
        bindingExpression.UpdateTarget();
    }

    private Binding GetBinding(string format)
    {
        var binding = new Binding();
        binding.Path = Path;
        binding.Converter = Converter;
        binding.ConverterCulture = ConverterCulture;
        binding.ConverterParameter = ConverterParamter;
        binding.StringFormat = format;
        return binding;
    }
}

样本使用情况:

XAML

代码语言:javascript
运行
复制
<TextBlock Text="{local:FormattedBinding Path=Nh3}"  />

<!-- specify price US currency -->
<TextBlock Text="{local:FormattedBinding Path=Price, ConverterCulture='en-US'}" />

<!-- specify price German currency -->
<TextBlock Text="{local:FormattedBinding Path=Price, ConverterCulture='de-DE'}" />

<!-- specify price Japanese currency -->
<TextBlock Text="{local:FormattedBinding Path=Price, ConverterCulture='ja-JP'}" />

<TextBlock Text="{local:FormattedBinding Path=Today}" />

ViewModel properties

代码语言:javascript
运行
复制
[DisplayFormat(DataFormatString = "{0:n4} %")]
public double Nh3 { get; set; }

[DisplayFormat(DataFormatString = "{0:C}")]
public decimal Price { get; set; }

[DisplayFormat(DataFormatString = "{0:dddd, MMMM dd}")]
public DateTime Today { get; set; }

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45642239

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档