WPF 中的动态条件格式
Dynamic Conditional Formatting in WPF
我正在开发一个工程程序,它的所有计算都用 VB.net 写在一个单独的项目中,我们现在把它放在 WPF UI 后面 UI。
我 运行 遇到了在单元之间更改字符串格式的问题。例如:在英制单位中,您的值为 4,966 lbf,转换后为 22.1 kN。您可以看到,有必要在 2 之间使用不同的格式,因为它们的数量级不同。
程序中目前设置的是条件着色(正常数字为黑色,错误为红色,警告为黄色)这些是通过资源字典中的样式设置的。
<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>
然后是多值转换器:
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;
}
}
我尝试过的:
所以这里的问题是,与 ValueShow.TensionStatusShow
不同,我想将字符串格式 "rules" 保留在 VB 计算方法之外。目前我们有 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
调用。这显然没有用,它会成功加载资源,但它忽略了字符串格式。我通过向加载良好的 Metric 资源添加背景颜色进行测试,但再次忽略了字符串格式。
我还尝试通过编程方式将字符串格式添加到 MultiValueConverter 中修改样式,但 运行 到 IsSealed
属性 中,我似乎无法击败
很抱歉快速&简短&不完整和间接的响应,但我想给你一个经常被忽视的解决方案。有时,当某些绑定或样式变得过于复杂并开始失败并且似乎无法追踪原因时,或者当我发现我可以从额外的解耦中受益时,我有时会使用它。
几乎所有的样式,触发器和复杂的绑定+MultiValueCoverters,你可以改写成所谓的"Attached behavior"。
See this article 快速浏览一下。注意这两种方式,附加属性和额外的子元素。
实际上,我喜欢同时使用两者的优点。因为我只想给你留言,所以我删减了这个答案并将冗长的文字移至 this article.
我知道这不能回答您关于样式和绑定为何不起作用的问题,但我仍然认为它可能对您有所帮助。您的样式和绑定似乎复杂到难以调试,我目前无法专注于此:|问题在于,通过尝试将值放在错误的 scope/level 上,绑定很容易被破坏(分离、覆盖),甚至样式和触发器中的设置器也可以将它们与目标取消链接。我感觉到这就是正在发生的事情,但我不会有更多的时间来帮助你在不久的将来追踪它。所以..祝你好运,我希望有人能给你一个更好的回应。
我正在开发一个工程程序,它的所有计算都用 VB.net 写在一个单独的项目中,我们现在把它放在 WPF UI 后面 UI。
我 运行 遇到了在单元之间更改字符串格式的问题。例如:在英制单位中,您的值为 4,966 lbf,转换后为 22.1 kN。您可以看到,有必要在 2 之间使用不同的格式,因为它们的数量级不同。
程序中目前设置的是条件着色(正常数字为黑色,错误为红色,警告为黄色)这些是通过资源字典中的样式设置的。
<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>
然后是多值转换器:
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;
}
}
我尝试过的:
所以这里的问题是,与 ValueShow.TensionStatusShow
不同,我想将字符串格式 "rules" 保留在 VB 计算方法之外。目前我们有 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
调用。这显然没有用,它会成功加载资源,但它忽略了字符串格式。我通过向加载良好的 Metric 资源添加背景颜色进行测试,但再次忽略了字符串格式。
我还尝试通过编程方式将字符串格式添加到 MultiValueConverter 中修改样式,但 运行 到 IsSealed
属性 中,我似乎无法击败
很抱歉快速&简短&不完整和间接的响应,但我想给你一个经常被忽视的解决方案。有时,当某些绑定或样式变得过于复杂并开始失败并且似乎无法追踪原因时,或者当我发现我可以从额外的解耦中受益时,我有时会使用它。
几乎所有的样式,触发器和复杂的绑定+MultiValueCoverters,你可以改写成所谓的"Attached behavior"。
See this article 快速浏览一下。注意这两种方式,附加属性和额外的子元素。
实际上,我喜欢同时使用两者的优点。因为我只想给你留言,所以我删减了这个答案并将冗长的文字移至 this article.
我知道这不能回答您关于样式和绑定为何不起作用的问题,但我仍然认为它可能对您有所帮助。您的样式和绑定似乎复杂到难以调试,我目前无法专注于此:|问题在于,通过尝试将值放在错误的 scope/level 上,绑定很容易被破坏(分离、覆盖),甚至样式和触发器中的设置器也可以将它们与目标取消链接。我感觉到这就是正在发生的事情,但我不会有更多的时间来帮助你在不久的将来追踪它。所以..祝你好运,我希望有人能给你一个更好的回应。