【问题标题】:Dynamic Conditional Formatting in WPFWPF 中的动态条件格式
【发布时间】:2015-01-09 14:57:58
【问题描述】:

我正在开发一个工程程序,该程序的所有计算都用 VB.net 编写在一个单独的项目中,我们现在将它放在 WPF UI 后面。

我遇到了在单位之间更改字符串格式的问题。例如:在英制单位中,您的值为 4,966 lbf,转换为 22.1 kN。您可以看到,两者之间必须有不同的格式,因为它们是不同的数量级。

程序中当前设置的是条件着色(黑色表示正常数字,红色表示错误,黄色表示警告)这些是通过资源字典中的样式设置的。

<Style x:Key="GlobalUserEditedTextBox" BasedOn="{StaticResource {x:Type TextBox}}" TargetType="TextBox">
     <Setter Property="Foreground" Value="{DynamicResource EditableTextColor}"/>
     <Setter Property="FontWeight" Value="Bold"/>
</Style>
<Style x:Key="GlobalErrorTextBox" BasedOn="{StaticResource {x:Type TextBox}}" TargetType="TextBox">
     <Setter Property="Foreground" Value="{DynamicResource ErrorTextColor}"/>
     <Setter Property="FontWeight" Value="Normal"/>
</Style>

在程序中,使用 Converter 和 MultiBinding 选择样式。 ValueShow.TensionStatusShow是VB计算代码出来的枚举值:

<TextBlock HorizontalAlignment="Stretch" TextAlignment="Center" Text="{Binding Path=ValueShow.TensionShow}">
    <TextBlock.Style>
        <MultiBinding Converter="{StaticResource styleConverter}">
            <MultiBinding.Bindings>
                <Binding RelativeSource="{RelativeSource Self}"/>
                <Binding Path="ValueShow.TensionStatusShow"/>
            </MultiBinding.Bindings>
        </MultiBinding>
    </TextBlock.Style>
</TextBlock>

然后是 MultiValueConverter:

public class StyleConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            FrameworkElement targetElement = values[0] as FrameworkElement;
            Style _newStyle;
            try
            {
                if (values[1] == null || values[1] == DependencyProperty.UnsetValue)
                    return null;

                if ((String)values[1] == StatusColor.ErrorValue.ToString())
                {
                    if (values[0].GetType() == typeof(TextBox))
                        _newStyle = (Style)targetElement.TryFindResource("GlobalErrorTextBox");
                    else if (values[0].GetType() == typeof(TextBlock))
                        _newStyle = (Style)targetElement.TryFindResource("GlobalErrorTextBlock");
                    else
                        _newStyle = null;
                } 
                else if
                {
                    if (values[0].GetType() == typeof(TextBox))
                        _newStyle = (Style)targetElement.TryFindResource("GlobalWarningTextBox");
                    else if (values[0].GetType() == typeof(TextBlock))
                        _newStyle = (Style)targetElement.TryFindResource("GlobalWarningTextBlock");
                    else
                        _newStyle = null;
                }
                return _newStyle;
            }
            catch (Exception)
            {
                if (values[0].GetType() == typeof(TextBox))
                    return (Style)targetElement.TryFindResource("GlobalUnEditableTextBox");
                else if (values[0].GetType() == typeof(TextBlock))
                    return (Style)targetElement.TryFindResource("GlobalUnEditableTextBlock");
                else
                    return null;
            }
        }

我尝试过的: 所以这里的问题是我想将字符串格式化“规则”排除在VB计算方法之外,这与ValueShow.TensionStatusShow不同。目前我们有 2 个资源字典(英制和公制)保存单位标签的字符串。我尝试在那里设置不同的字符串格式,以便在程序更改单位时更新。

帝国资源:

<s:String x:Key="UnitsStringFormatlbfkN">F0</s:String>
<Style TargetType="TextBox" x:Key="GlobalErrorTextBoxlbkNFormatting" BasedOn="{StaticResource GlobalErrorTextBox}">
        <Setter Property="Text" Value="{Binding Path=., Mode=TwoWay, StringFormat={StaticResource UnitsStringFormatlbfkN}}" />
    </Style>

指标资源

<s:String x:Key="UnitsStringFormatlbfkN">F1</s:String>
<Style TargetType="TextBox" x:Key="GlobalErrorTextBoxlbkNFormatting" BasedOn="{StaticResource GlobalErrorTextBox}">
        <Setter Property="Text" Value="{Binding Path=., Mode=TwoWay, StringFormat={StaticResource UnitsStringFormatlbfkN}}" />
    </Style>

然后我将lbkNFormatting 作为多重绑定中的第三个参数传递,并将其附加到TryFindResourcecall。这显然不起作用,它会成功加载资源,但它忽略了字符串格式。我通过向加载正常的 Metric 资源添加背景颜色进行了测试,但再次忽略了字符串格式。

我还尝试通过以编程方式添加字符串格式来修改 MultiValueConverter 中的样式,但遇到了我似乎无法击败的 IsSealed 属性

【问题讨论】:

  • 您是否尝试将 StringFormat 更改为 DynamicResource 而不是 static?
  • 我刚刚尝试过,我收到以下错误:无法在“Binding”类型的“StringFormat”属性上设置“DynamicResourceExtension”。只能在 DependencyObject 的 DependencyProperty 上设置“DynamicResourceExtension”。

标签: c# wpf xaml


【解决方案1】:

很抱歉快速&简短&不完整和间接的回应,但我想给你一个经常被忽视的解决方案。当某些绑定或样式变得过于复杂并开始失败并且似乎无法追踪原因时,或者当我发现我可以从额外的解耦中受益时,我有时会使用它。

几乎所有的样式、触发器和复杂的绑定+MultiValueCoverters,都可以改写成所谓的“附加行为”。

See this article 快速浏览。注意这两种方式,附加属性和额外的子元素。

实际上,我喜欢同时使用两者中最好的。由于我只想给您留个便条,因此我已删除此答案并将聊天文本移至this article

我知道这并不能回答您关于 Style&Binding 为什么不起作用的问题,但我仍然认为您可能会发现它有帮助。您的样式和绑定似乎足够复杂,难以调试,我目前无法专注于:|问题在于,通过尝试将值放在错误的范围/级别上,很容易破坏(分离、覆盖)绑定,甚至样式和触发器中的设置器也可以将它们与目标解除链接。我感觉这就是正在发生的事情,但在不久的将来我不会有更多时间来帮助您追踪它。所以.. 祝你好运,我希望有人设法给你一个更好的回应。

【讨论】:

  • 谢谢!这看起来是一个非常有用的功能。我从未听说过 Attached Behavior,但听起来它应该对我们在尝试使用动态样式时遇到的问题有很大帮助。
  • 所以我已经在静态类 AttachedValue 中设置了 3 个属性(SourceValue、Units 和 DisplayValue),但我遇到了文本绑定问题。 Text="{Binding (AttachedValue.DisplayValue), RelativeSource=Self}" 编译器抱怨它找不到 AttchedValue,并且当它运行时,相对源尝试将字符串转换为相对源时出错。你知道会发生什么吗?或者我应该更新我的代码来查看吗?
  • @user3565590:我是凭记忆写的。请改用RelativeSource={RelativeSource Self}。关于(AttachedValue.DisplayedValue) 绑定,尝试使用命名空间前缀作为前缀,即(myns:AttachedValue.DisplayedValue),将myns 替换为您命名空间的正确前缀。如果这不起作用,请尝试添加显式 Path 属性,即:Fooo="{Binding Path=(myns:AttachedValue.DisplayedValue), ..." 当 WPF 无法弄清楚如何解析表达式时,它会有所帮助,它有时会发生。
  • 所以添加命名空间和RelativeSource 修复了编译问题并运行,但我没有得到GetDisplayValue 函数被调用。我感觉它与您附加的my:AutoUnitConversionfunction 有关。您在帖子中提到了这一点,但我不确定它/应该在做什么。这应该是静态类AttachedValue 中的一个方法,它获取所有属性并计算一个字符串以返回给 xaml?
  • @user3565590:附加绑定UnitSourceSourceValue属性,创建DisplayValue属性后,就得到了基本的数据链接。现在您需要一些能够实际执行工作的东西:必须注意 UnitSource 和 SourceValue 的变化,当发生这种变化时,必须计算出您想要的东西,然后设置 DisplayedValue。外面真的没有免费的午餐。你有两个选择
猜你喜欢
  • 2019-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-27
  • 1970-01-01
相关资源
最近更新 更多