# .NET and More > WPF, WCF, WF >  A Beginners Naivety - Varaibles

## librarat

I'm just learning WPF apps and have been looking for a good tutorial on how variables work within the WPF model, but really haven't been able to find something.  Subsequently, I'm a bit stuck :S

I feel like I'm trying to do something basic here, but maybe I'm just off my rocker. All I'm trying to do is onSelectionChanged of a dropdown, run function XXX.  Function XXX, at run, populates a variables then writes the variable to a label.  I'll post code snippets.  But what am I missing?

DropDown Code


```
<ComboBox Canvas.Left="223" Canvas.Top="261" Height="23" Name="userTempScale" Width="54" Background="{x:Null}" BorderBrush="#FF992907" BorderThickness="0" Foreground="#FF992907" HorizontalContentAlignment="Center">
            <ComboBoxItem Content="F" IsSelected="True" />
            <ComboBoxItem Content="C" />
            <ComboBoxItem Content="K" />
            <ComboBoxItem Content="Re" />
            <ComboBoxItem Content="Ra" />
        </ComboBox>
```

Dropdown Handler Code


```
    Private Sub userTempScale_SelectionChanged(ByVal sender As Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs) Handles userTempScale.SelectionChanged
        calculateTemps() ' Update our Temps 
    End Sub
```

Function XXX code


```
Public Function calculateTemps() As Action
Dim tempscale As String = userTempScale.SelectedItem.ToString
If tempscale = "F" Then
fah_label.Content = tempscale
endif
```

Like I said, pretty basic but I seem to be missing a connection between WPF and WinForms.  Anyone got a wrench to smack me over the head with?  :Smilie:

----------


## librarat

I need to learn how to use the preview button as I can't seem to edit my post >.< Sorry guys...

----------


## techgnome

you can't edit your posts until your post count gets a little higher, but no worries....

I'm a little unclear on what the problem is exactly... is something happening that shouldn't? Or is something not happening that should? Or... ?????

Ah... let me guess... you're having trouble getting the SelectionChanged event to fire off...
If I remember right (I can't check this at the moment...) you need to add to your combobox tag... the name of the event as an attribute, and its value set to the name of the event handler....

Like this:


```
SelectionChanged="MySelectionChangedHandler"
```

I think that's right.

FYI - we do have a WPF specific forum here... guys in there are pretty good at this stuff... better than me. I'll have it moved there, and get that code tag of yours fixed up.

-tg

----------


## Hack

_Moved To WPF, WCF, WF and fixed Code tag_

Thanks for the report tg!   :Thumb:

----------


## librarat

Thank you techgnome - for the reply and the codetag fix  :Smilie: 
Not sure how I missed the WPF forums ... I'll add your suggestion in.  

I suppose I should have added the issue...

1) When I add a breakpoint on the sub, at runtime the breakpoint fires off without the event actually being called.  
2) When I change the selection in the textbox, nothing happens to my label...

I spoke with a professor at my school about WPF apps and he clearly doesn't know about them. He sent me an email a few hours later basically telling me that I need to write my own handler for each event (which you don't have to do in WinForms)  

Subsequently, I'm a bit lost.

----------


## librarat

After adding in your suggestion, I now get the following error


```
Error	2	'MySelectionChangedHandler' is not a member of 'WpfApplication1.MainWindow'.	C:\Users\Skippy\Desktop\WPF Apps\Temperature Converter\Temperature Converter\obj\x86\Debug\MainWindow.g.vb	153	126	Temperature Converter
```

Given that, I'm starting to thing that I do need to create my own classes/event handler?  If so, I feel as I'm over my head  :Frown:

----------


## techgnome

I jsut stuck in the name "MySelectionChangedHandler" as a place holder... you need to replace it with the actual name of the event handler... which you have... userTempScale_SelectionChanged is your event handler. But if it's firing off when you run the app... it's wired up so you may not need to do anything more with that.

that said... the reason the event fires off when you run it even when you don't make a selection... is because a selection is being made... the default one.... that's what this little bit is doing: 
IsSelected="True"

Now, as to why it then doesn't work any more after that.... I'm guessing there's more to your code than just the one if statement, right? Like... the if statements for all of the other selections? And they all display something different? Even if you have to hard-code it for the time being... be sure that much at least is working.

-tg

----------


## Megalith

> Thank you techgnome - for the reply and the codetag fix 
> Not sure how I missed the WPF forums ... I'll add your suggestion in.  
> 
> I suppose I should have added the issue...
> 
> 1) When I add a breakpoint on the sub, at runtime the breakpoint fires off without the event actually being called.  
> 2) When I change the selection in the textbox, nothing happens to my label...
> 
> I spoke with a professor at my school about WPF apps and he clearly doesn't know about them. He sent me an email a few hours later basically telling me that I need to write my own handler for each event (which you don't have to do in WinForms)  
> ...


1/ the event fires because you have set the default to "F" 
(<ComboBoxItem Content="F" IsSelected="True" />)

2/ the Textbox will need to have TextChanged event in the code as suggested by your prof (not sure if that is the actual event name, double clicking the textbox should create the event automatically for you)

@TG took me 15 mins to press the submit post there lol

----------


## bflosabre91

because you specifically state "Handles userTempScale.SelectionChanged" for the Sub, you don't have to put a reference to that in the xaml as long as that combobox is actually named userTempScale. I think the issue you are getting is with using the combobox.SelectedItem.ToString. The selected item is probably returning the entire object of type ComboboxItem, not the content which i think is what you want. The easiest way to fix would be to change ur function to this.



```
Public Function calculateTemps() As Action
Dim item as ComboBoxItem = Ctype(userTempScale.SelectedItem,ComboBoxItem)
Dim tempscale As String = item.Content
If tempscale = "F" Then
fah_label.Content = tempscale
end if
```

----------


## librarat

Gah, I figured that was a VB reference, not just a placeholder >.<

For grins and giggles, I'll post the rest of my code.

I have two real issues (one of which I suspect is fixed as per your suggestions, tg).
1) onSelectionUpdate wasn't calling the function / running the sub
2) I can't seem to set variables to the values of either a textbox or the dropdown.
For the variables that I'm trying to set in the function, I get the following error for the second variable (no idea why).  The variable line is itself highlighted during debugging.


```
Object reference not set to an instance of an object.
```



```
Class MainWindow

    Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
        My.Computer.Audio.Play(My.Resources.superhero, AudioPlayMode.Background)
    End Sub

    Private Sub Button1_click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click

        If Button1.Content = "Stop Audio" Then
            My.Computer.Audio.Stop()
            Button1.Content = "Start Audio"
        Else
            My.Computer.Audio.Play(My.Resources.superhero, AudioPlayMode.Background)
            Button1.Content = "Stop Audio"
        End If

    End Sub

    Private Sub userTempScale_SelectionChanged(ByVal sender As Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs) Handles userTempScale.SelectionChanged
        calculateTemps() ' Update our Temps 
    End Sub

    Private Sub inputtedtemperature_TextChanged(ByVal sender As Object, ByVal e As System.Windows.Controls.TextChangedEventArgs) Handles inputtedtemperature.TextChanged
        calculateTemps() ' Update our Temps
    End Sub

    Private Sub buttonClose_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles buttonClose.Click
        Me.Close()
    End Sub

    Public Function calculateTemps() As Action

        'Just for shits and giggles, lets update all of our label boxes here with what ever is in the updated (onchange) field


        ' This function updates the 5 temperature fields, idealls on change of *EITHER*
        '   the input field or the select box

        ' The code below merely updates the values in the texboxes that displays converted temp

        ' Input: tempConvert
        ' Type : tempScale

        ' Labels:
        '   F:  fah_label
        '   C:  cel_label
        '   K:  kel_label
        '   Re: ren_label
        '   Ra: ram_label

        ' 1 = Temperature Scale Selected Update
        ' 0 = Temperature (number) Updated

        ' First, let's populate our variables.
        Dim tempscale As String = userTempScale.SelectedItem.ToString
        Dim tempinput As Integer = Val(inputtedtemperature.Text) ' We need to make sure that the input is only numbers or ****'s gonna' go to hell in a handbasket

        ' Friggin' woot! Let's get these nested if's going here...
        ' Here's how this works, based on what SCALE is selected
        '   the IF changes to update labels 
        If tempscale = "F" Then

            fah_label.Content = tempinput
            cel_label.Content = (tempinput - 32) * (5 / 9)
            kel_label.Content = ((tempinput - 31) * (5 / 9)) + 273.15
            ren_label.Content = (tempinput - 32) / 2.25
            ram_label.Content = tempinput + 459.67


        ElseIf tempscale = "C" Then

            fah_label.Content = (tempinput * (9 / 5)) + 32
            cel_label.Content = tempinput
            kel_label.Content = tempinput + 273.15
            ren_label.Content = tempinput * 0.8
            ram_label.Content = (tempinput * (1.8)) + 32 + 459.67


        ElseIf tempscale = "K" Then

            fah_label.Content = (tempinput - 273.15) * (9 / 5) + 32
            cel_label.Content = tempinput - 273.15
            kel_label.Content = tempinput
            ren_label.Content = (tempinput - 273.15) * 0.8
            ram_label.Content = tempinput * 1.8


        ElseIf tempscale = "Re" Then

            fah_label.Content = (tempinput * (2.25)) + 32
            cel_label.Content = tempinput * 1.25
            kel_label.Content = (tempinput * 1.25) + 273.15
            ren_label.Content = tempinput
            ram_label.Content = (tempinput * 2.25) + 32 + 459.67


        ElseIf tempscale = "Ra" Then

            fah_label.Content = tempinput - 459.67
            cel_label.Content = (tempinput - 32 - 495.67) / 1.8
            kel_label.Content = tempinput / 1.8
            ren_label.Content = (tempinput - 32 - 495.67) / 2.25
            ram_label.Content = tempinput


        End If

    End Function

End Class
```

----------


## librarat

bflosabre91 - Thank's for that. I ran a quick test, and that was indeed a problem!  Solved the function not doing anything warning, too.  The second variable I'm still stuck at, as I can't use CType for the textbox (in the same manner as you described above)

----------


## bflosabre91

where is the code you are using to get the value of the textbox? my guess is the error you are getting is because you are using the same function to set the values of your variables but if you don't have a value selected in the combobox and you fire the text changed event, it will error when trying to get the value of the combobox because nothing was selected yet. make sure you check to see if the controls have a value before you set the variable equal to the value, if that makes sense..

----------


## librarat

```
inputtedtemperature.Text
```

Does this not get the value of a textbox, as well as set the text? The help says the .Text operator does that.

----------


## librarat

```
Dim tempInput = inputtedtemperature.Text
```

Gives me...


```
System.NullReferenceException was unhandled by user code
  Message=Object reference not set to an instance of an object.
```

But I have no idea why  :Frown:

----------


## bflosabre91

try



```
Dim tempInput as String = inputtedtemperature.Text
```

----------


## librarat

Exact same error message with that added :-\

----------


## bflosabre91

where are you running that code to set the value of tempInput? You probably shouldn't do it in the textchange event because that will run everytime the text is changed, so if you type "test", it will run 4 separate times. and what is the code that you are using the tempInput for?

----------


## librarat

The variable is declared and populated from inside the function (see the full source I posted above).  The idea is to actually update/run the function every time a keystroke occurs, though I suppose I could just add a button to run the function...   Regardless, am I missing something? Do I need to declare the variable outside of the function?

----------


## bflosabre91

well it depends on what your using the variable for. If you need the variable outside the function, then yes you need to declare it outside of the function and just set the value inside the function. If you are just returning a value based on the value of the textbox, then you may not even need to declare a variable at all, or you might just be fine with declaring it inside the function

----------


## librarat

Ok. The Var isn't being used outside the function.  Ive set two (or am trying to set two..) variables inside, like so...


```
        Dim tempComboBox As ComboBoxItem = CType(userTempScale.SelectedItem, ComboBoxItem)
        Dim tempscale As String = tempComboBox.Content

        Dim tempInput As String = inputtedtemperature.Text
```

The first variable seems to work alright. It's second that gives me the trouble, and prevents a build.  What's missing?

----------


## techgnome

my two centavos... the variable isn't the problem. When the code breaks... it should be highlighhting the line with the error... check EVERYTHING by mousing over it and see WHICH object is nothing... I'm betting it's this one...inputtedtemperature


Waaaaait a minute... "prevents a build" ... if it's preventing a build, then you have a red squiggly underneath it and it should be listed in the Errors list and should tell you EXACTLY what is wrong...

something isn't kosher here... the error about an object reference not being set is a runtime error, but should NOT be holding up the build... you should still be able to build.

Did we move on to a new problem and I missed it? of what's going on here?

-tg

----------


## bflosabre91

i think it just hit me. this function gets called on textbox_textchanged and comboxbox_selectionchanged right? i think the issue is that when the combobox is created, the selectionchanged event gets fired and so does your function which breaks because the textbox hasnt been created yet. Try breaking up the function into 2 functions, 1 for the comboxbox and 1 for the textbox.

----------


## librarat

TG - When I say prevents a build, the build stops (not sure how to skip it?) and that line is highlighted in yellow, with a popup box and a line drawn to the highlighted part... Can I make my newbishness any more evident? >.<   So no, we haven't moved on to a new problem  :Smilie:    No red squiggly, not even a blue one.  

I'll see if I can break up the function, but having a background in PHP, I feel that that's really just a waste of time... :-\

----------


## bflosabre91

well you dont have to break the function up if it doesnt make sense to. you really havent shown what your function even does. you can keep the same function but inside the selectionchanged and textchanged events, put an if statement in there to check if the textbox.text has value, if not then dont run the function. same thing for the combobox, if it doesnt have a value, then the function should not be running.

----------


## librarat

I added the check for empty, and it's not throwing any exceptions.  Nor is it breaking at the breakpoints I've set (since both have defaults).  The issue is still on that variable line.  I'll add screenshots....

----------


## techgnome

OK.. that's a Run-Time error... not one that "stops the build" ... which has a completely different meaning.

If you then highlight, by double-clicking inputtedTemperature ... then mouse over it... you'll get a tooltip that tells you about the item selected... I bet... it will tell you that it " = Nothing" ... At the time the function is running inputtedTemperature *does_not_exist* ...

-tg

----------


## librarat

double-clicking inputtedtemperature and hovering does nothing.  There are no lines (either red or blue) at all in the code window.  I get no tooltip as per your suggestion >.<

----------


## techgnome

you have to do it when the error is thrown and the entire line is highlighted in yellow... don't hit the stop button or anything. if the tool tip still doesn't work... then right-click and select "Quick Watch" that will open a new window that will tell you the value of the variable... and if it's not nothing, you should be able to see all the properties and values of those properties... if it is Nothing, you'll see an error similar to the problem being experienced.

-tg

----------


## bflosabre91

does the error occur when you select the value of the combobox or when you text in the textbox?

----------


## librarat

After digging deeper here... I have figured out that it's the way in which I'm trying to access the methods -> I cannot simply do the following from within a function.  However, the exact thing works just fine if called from within the sub for the event.  Why?


```
fah_label.Content = inputTemperature.Text
```

^ This DOES NOT work (see error below) from within a function, but DOES work if used directly in the sub.  See original code...


```
{"Object reference not set to an instance of an object."}
```

Thoughts?

----------


## librarat

When I try to declare variables within the function using the following, I get the following error:


```
 Dim inputTemperature As String
        inputTemperature = userTempInput.Text
```



```
Error	2	'Text' is not a member of 'String'.
```

Which data type should I be using, if not a string - I've tried a short and int, but I get the same issue...

----------


## librarat

Ehh, I figured out the issues I was posting about previously.  Now, I'm back to where we started....

----------


## bflosabre91

does the error occur when you first run the app, when the combobox selection changes or when the textbox text changes?

----------


## Megalith

suggest the op steps through his routine (F8), looks to me that these methods are being called before the interface is displayed. if so the op needs to make sure the value is not updated until the ui is displayed.

----------


## Evil_Giraffe

Are you aware that you're really working against the grain of WPF doing it how you're doing it?  You shouldn't be hooking on to control events, instead you should be binding controls to instances of classes and handling all these changes inside the classes.  Here's an example for your temperature conversion:

First up, let's create a simple structure to hold all our calculated temperatures in.  (Make sure you make these properties not just fields, because we're going to get WPF to bind to them later on.)


vbnet Code:
Public Structure TemperatureValues
    Public Property Fahrenheit As Decimal
    Public Property Celsius As Decimal
    Public Property Kelvin As Decimal
    Public Property Ren As Decimal
    Public Property Ram As Decimal
End Structure

Okay, now we want to select the temperature that we're converting from in our UI, so instead of slinging strings about, let's model a TemperatureConverter and actual have those floating about.  We can then use WPF to style them into something we can see (for example displaying a string)

Now, because we have a predefined set of valid converters, we can take advantage of the Enum Object Pattern to create a strongly typed set of values (like an enum) that are actually objects:


vbnet Code:
Public MustInherit Class TemperatureConverter
     Public Shared ReadOnly Fahrenheit As TemperatureConverter = New FahrenheitTemperatureConverter
    Public Shared ReadOnly Celsius As TemperatureConverter = New CelsiusTemperatureConverter
    ' ... an instance of the rest of the converters go here
     Private Sub New()
     End Sub
     MustOverride ReadOnly Property TemperatureScaleAbbreviation As String
    MustOverride Function ConvertTemperatues(ByVal temperature As Decimal) As TemperatureValues
     Private Class FahrenheitTemperatureConverter
        Inherits TemperatureConverter
         Public Overrides ReadOnly Property TemperatureScaleAbbreviation As String
            Get
                Return "F"
            End Get
        End Property
         Public Overrides Function ConvertTemperatues(ByVal temperature As Decimal) As TemperatureValues
             Dim temperatureValues As New TemperatureValues()
            temperatureValues.Fahrenheit = temperature
            temperatureValues.Celsius = (temperature - 32) * (5D / 9)
            temperatureValues.Kelvin = ((temperature - 31) * (5D / 9)) + 273.15D
            temperatureValues.Ren = (temperature - 32) / 2.25D
            temperatureValues.Ram = temperature + 459.67D
             Return temperatureValues
         End Function
     End Class
     Private Class CelsiusTemperatureConverter
        Inherits TemperatureConverter
         Public Overrides ReadOnly Property TemperatureScaleAbbreviation As String
            Get
                Return "C"
            End Get
        End Property
         Public Overrides Function ConvertTemperatues(ByVal temperature As Decimal) As TemperatureValues
             Dim temperatureValues As New TemperatureValues()
            temperatureValues.Fahrenheit = (temperature * (9D / 5)) + 32
            temperatureValues.Celsius = temperature
            temperatureValues.Kelvin = temperature + 273.15D
            temperatureValues.Ren = temperature * 0.8D
            temperatureValues.Ram = (temperature * 1.8D) + 32 + 459.67D
             Return temperatureValues
         End Function
     End Class
     ' Define rest of the converters here...
End Class

Now, you create a ViewModel for your window.  You'll need to expose the following:
a collection of convertersthe _currently selected_ converterthe input temperature valuethe outputted temperature values
Something like this:


vbnet Code:
Imports System.ComponentModel
 Public Class TemperatureConverterViewModel
    Implements INotifyPropertyChanged
     Dim _temperature As Decimal
    Dim _selectedConverter As TemperatureConverter = TemperatureConverter.Fahrenheit
    Dim _converters As List(Of TemperatureConverter) = New List(Of TemperatureConverter)
    Dim _calculatedTemperatures As TemperatureValues
       Public Sub New()
        _converters.Add(TemperatureConverter.Fahrenheit)
        _converters.Add(TemperatureConverter.Celsius)
        RefreshCalculatedTemperatures()
    End Sub
     Public ReadOnly Property Converters As IEnumerable(Of TemperatureConverter)
        Get
            Return _converters
        End Get
    End Property
     Public Property SelectedConverter As TemperatureConverter
        Get
            Return _selectedConverter
        End Get
        Set(ByVal value As TemperatureConverter)
            If Not Object.ReferenceEquals(_selectedConverter, value) Then
                _selectedConverter = value
                RefreshCalculatedTemperatures()
                OnPropertyChanged("SelectedConverter")
            End If
        End Set
    End Property
    Public Property Temperature As Decimal
        Get
            Return _temperature
        End Get
        Set(ByVal value As Decimal)
            If value <> _temperature Then
                _temperature = value
                RefreshCalculatedTemperatures()
                OnPropertyChanged("Temperature")
            End If
        End Set
    End Property
     Public Property CalculatedTemperatures As TemperatureValues
        Get
            Return _calculatedTemperatures
        End Get
        Private Set(ByVal value As TemperatureValues)
            _calculatedTemperatures = value
            OnPropertyChanged("CalculatedTemperatures")
        End Set
    End Property
     Protected Sub OnPropertyChanged(ByVal propertyName As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub
    Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
     Private Sub RefreshCalculatedTemperatures()
        If Not IsNothing(_selectedConverter) Then
            CalculatedTemperatures = _selectedConverter.ConvertTemperatues(_temperature)
         End If
    End Sub
 End Class

Note that for the output, we're not outputting each value individually, we'll leave that to WPF's databinding to sort out later.

Create one of these and assign it as the DataContext of your window and then bind your controls to it ( code coming in next post due to size limits):

Things to note:
The Combo box must bind both ItemsSource and SelectedItemCombo Box's DisplayMemberPath must match property name defined on the TemperatureConverter classTextBox's UpdateSourceTrigger in the binding means it will update as you type in the textbox

Now WPF won't be fighting you every step of the way  :Smilie:

----------


## Evil_Giraffe

MainWindow.xaml:




```
<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <ComboBox ItemsSource="{Binding Converters}" DisplayMemberPath="TemperatureScaleAbbreviation"
                  SelectedItem="{Binding SelectedConverter}"/>
        <TextBox Text="{Binding Temperature, UpdateSourceTrigger=PropertyChanged}" />
        
        <Label Content="Fahrenheit" />
        <TextBlock Text="{Binding CalculatedTemperatures.Fahrenheit, StringFormat=n2}" />

        <Label Content="Celsius" />
        <TextBlock Text="{Binding CalculatedTemperatures.Celsius, StringFormat=n2}" />

        <Label Content="Kelvin" />
        <TextBlock Text="{Binding CalculatedTemperatures.Kelvin, StringFormat=n2}" />

        <Label Content="Ren" />
        <TextBlock Text="{Binding CalculatedTemperatures.Ren, StringFormat=n2}" />

        <Label Content="Ram" />
        <TextBlock Text="{Binding CalculatedTemperatures.Ram, StringFormat=n2}" />
    </StackPanel>
</Window>
```

----------

