0

I have a XAML file with a bunch of TextBlocks in them, and a button with a tag which contains the average of those values. The code for the button is this:

<Button x:Name="ltavg_button" Cursor="Hand" Grid.Row="1" Grid.Column="3" FontSize="20"
          Width="230"
          Content="&lt; Average Systolic"
          Tag="116.21428571428571"
          Click="ltavg_button_Click"/>

The code is supposed to change the foreground of the TextBlock to Grey, and to do that it takes the value from the button's tag, and then value for the textblocks (which are in a list), and then compares to them to each other. The problem is that the tag is being converted to some weird value that doesn't make any sense.

The listener code, in C#:

 private void gtavg_button_Click(object sender, RoutedEventArgs e)
 {
   Double avg = Double.Parse(ltavg_button.Tag.ToString());
   foreach (TextBlock tb in dia)
   {
     int txt = int.Parse(tb.Text);
     if (txt < avg)
     {
       tb.Foreground = new SolidColorBrush(DarkSlateGray);
     }
   }
 }

Because the avg value is so weird, it considers the condition true even if it shouldn't be. Some values are 110 or less, others are higher than 120

Any help is greatly appreciated, I've been pulling my hair out over this for a long time.

Smallwater
  • 364
  • 2
  • 10

2 Answers2

1

Ok. Delete all your code and start all over.

First of all, you have a SERIOUS misconception here: The UI is NOT the right place to store data.

Therefore, you should NOT be placing your numeric values in XAML, but instead you should create a proper ViewModel to store these numbers and operate on them:

<Window x:Class="MiscSamples.AverageNumbersSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="AverageNumbersSample" Height="300" Width="300">
    <DockPanel>
        <Button Content="Calculate" Click="Calculate" DockPanel.Dock="Top"/>
        <ListBox ItemsSource="{Binding}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Value}" x:Name="txt"/>
                    <DataTemplate.Triggers>
                        <DataTrigger Binding="{Binding IsBelowAverage}" Value="True">
                            <Setter TargetName="txt" Property="Foreground" Value="Blue"/>
                        </DataTrigger>
                    </DataTemplate.Triggers>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </DockPanel>
</Window>

Code Behind:

public partial class AverageNumbersSample : Window
{
    public double Average = 116.21428571428571;
    public List<AverageSampleViewModel> Values { get; set; } 

    public AverageNumbersSample()
    {
        InitializeComponent();
        DataContext = Values = Enumerable.Range(100, 150)
                                        .Select(x => new AverageSampleViewModel() { Value = x })
                                        .ToList();
    }

    private void Calculate(object sender, RoutedEventArgs e)
    {
        Values.ForEach(x => x.IsBelowAverage = x.Value < Average);
    }
}

Data Item:

public class AverageSampleViewModel: PropertyChangedBase
{
    public int Value { get; set; }

    private bool _isBelowAverage;
    public bool IsBelowAverage
    {
        get { return _isBelowAverage; }
        set
        {
            _isBelowAverage = value;
            OnPropertyChanged("IsBelowAverage");
        }
    }
}

PropertyChangedBase class (MVVM Helper)

public class PropertyChangedBase:INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        Application.Current.Dispatcher.BeginInvoke((Action) (() =>
                                                                 {
                                                                     PropertyChangedEventHandler handler = PropertyChanged;
                                                                     if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
                                                                 }));
    }
}

Result:

enter image description here

  • In this sense, WPF is fundamentally different from anything else currently in existence (such as the multiple dinosaur archaic UI frameworks available for java or stuff like that).
  • You must NEVER use the UI to store data, instead you use the UI to show data. These concepts are fundamentally different.
  • My example (which is the RIGHT way to do WPF applications), removes the need for int.Parse() or any casting stuff like that, because the ViewModel already has the proper data type required.
Community
  • 1
  • 1
Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154
0

You want to tell the Parse() method which culture you're using for the textual representation of the double value. In this case, the . is supposed to mean the decimal sign, but in other cultures it's used as a thousands delimiter. Change your call to the parse method to this:

Double avg = Double.Parse(ltavg_button.Tag.ToString(), CultureInfo.InvariantCulture);

and be sure to add

using System.Globalization;

to your using statements at the top. That'll tell Parse method that it should parse the Tag value using the invariant culture, which is what you want.

This may also explain why your comparison keeps returning true: it's possible that you're not comparing 110 or 120 against 116.21428571428571, but against 11621428571428571.0.

When calling Parse() or converting a number to a string using ToString(), always supply an IFormatProvider. Otherwise you never know what'll happen if your code runs on a machine with different culture settings.

Bas
  • 1,946
  • 21
  • 38
  • -1. This encourages the use of really bad practices. See my answer. – Federico Berasategui May 21 '13 at 15:07
  • I was aware of the bad practices, but I figured that if the OP has trouble with something as fundamental as the importance of culture when parsing/converting numeric numbers, telling him/her to change the entire architecture of the application is going to be beyond their current level of expertise. – Bas May 21 '13 at 15:32