Dynamic Conditional Formatting in WPF

I am working on an engineering program that has all the calculations written in VB.net in a separate project and now we are putting it in a WPF interface.

I am having a problem with changing the formats of strings between units. For example: in Imperial units you have a value of 4,966 pounds and convert that to 22.1 kN. You can see that it is necessary to have a different format between the two as they are in different orders.

Currently, the program has conditional coloring (black for a regular number, red for an error, yellow for a warning), which are configured through the styles in the resource dictionary.

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

      

In the program, the style is selected using a converter and a MultiBinding. ValueShow.TensionStatusShow

is the enum value coming out of the VB computation code:

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

      

And then the 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;
            }
        }

      

What I tried: So the problem is that I want to keep the "formatting" of the string formatting from VB calculation methods as opposed to ValueShow.TensionStatusShow

. We currently have 2 resource dictionaries (Imperial and Metric) that contain strings for unit labels. I tried setting up various string formats there so that it updates when the program changes units.

Imperial resource:

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

      

Metric resource

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

      

Then I would pass lbkNFormatting

as the third parameter in multi-linked mode and add it to the call TryFindResource

. Apparently it didn't work, but it loaded the resource successfully but ignored the string format. I tested by adding background colors to the Metric resource, which loaded fine, but again, the string format was ignored.

I also tried to change the style in the MultiValueConverter by programming the addition of string formatting, but encountering a property IsSealed

that I cannot beat

+3


source to share


1 answer


Sorry for the quick and short, not complete and indirect answer, but I wanted to throw you an often forgotten solution. I sometimes use it when some binding or style gets too complex and starts to fail and it seems impossible to trace why, or when I see that I could benefit from additional decoupling.

You can rewrite almost all styles, triggers and complex bindings + MultiValueCoverters into the so-called "bound behavior".

See the article for a quick look. Notice the two paths: added properties and additional subitems.



Actually, I like to use the best of both at the same time. Since I just wanted to throw you a note, I have truncated this answer and moved the text in this article .

I know this doesn't answer your question as to why styling and binding don't work, but I still think you might find it useful. Your styles and bindings seem complex enough to be difficult to debug and I can't focus on it: | The problem is that bindings can be very easily broken (disabled, overridden) trying to put the value on the wrong area / level, and even setters from styles and triggers can separate them from targets. I feel like this is what's happening, but I won't have more time to help you trace it in the near future. So ... good luck and I hope someone can give you a better answer.

+2


source







All Articles