WPF 中的动态条件格式

本文关键字:条件 格式 动态 WPF | 更新日期: 2023-09-27 18:37:06

我正在开发一个工程程序,该程序将所有计算都以 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>

在程序中,使用转换器和多重绑定选择样式。 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>

然后是多值转换器:

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作为多重绑定中的第三个参数传递,并将其附加到TryFindResource调用中。这显然不起作用,它将成功加载资源,但它忽略了字符串格式。我通过向加载良好的指标资源添加背景颜色进行测试,但同样,字符串格式被忽略了。

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

WPF 中的动态条件格式

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

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

请参阅本文以快速浏览。请注意两种方式,附加属性和额外的子元素。

实际上,我喜欢同时使用两者中最好的。由于我只想给您留言,因此我修剪了此答案并将聊天文本移至本文。

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