gpt4 book ai didi

c# - WPF 中 DisplayFormatAttribute 的推荐替代方法是什么?

转载 作者:太空宇宙 更新时间:2023-11-03 22:55:25 24 4
gpt4 key购买 nike

所以我找到了 DisplayFormatAttribute 类(我猜它只用于 Web 开发?)。它确实会在可维护性方面改进我的项目,因为我有许多小数属性,它们的小数位数似乎一次又一次地改变(客户要求与我的“聪明”想法混合在一起)。

基本上,我会有这样的属性:

[DisplayFormat(DataFormatString = "{0:n4} %")]
public decimal Nh3 {get; set;}

DisplayFormatAttribute 所示,需要在当前用户语言环境中显示四位小数,后跟一个 %。

在 XAML 中我会有类似的东西

<TextBlock Text="{Binding Nh3}"/>

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

对于特定的 TextBlock,这可以通过

实现
<TextBlock Text="{Binding Nh3, StringFormat={}{0:n4} %"/>

但正如我提到的那样,这是重复且容易出错的。

我见过有人用类似的东西

<TextBlock Text="{Binding Nh3, StringFormat={StaticResource Nh3Format} %"/>

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

最佳答案

您可以定义自己的 DisplayFormatAttributecustom markup-extension自动为您创建这些绑定(bind)。

///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

<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 属性

[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; }

enter image description here

关于c# - WPF 中 DisplayFormatAttribute 的推荐替代方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45642239/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com