Yorrick
Yorrick

Reputation: 377

NullReferenceException when a value is entered

Here's my entire code:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
    private void sldChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
        double red, green, blue;
        red = sldRed.Value;
        green = sldGreen.Value;
        blue = sldBlue.Value;
        changeColors(red, green, blue);
    }

    private void inputChanged(object sender, TextChangedEventArgs e)
    {
        double red, green, blue;
        red = Convert.ToDouble(txtRed.Text);
        green = Convert.ToDouble(txtGreen.Text);
        blue = Convert.ToDouble(txtBlue.Text);
        sldRed.Value = red;
        sldGreen.Value = green;
        sldBlue.Value = blue;
        changeColors(red, green, blue);
    }

    void changeColors(double red, double green, double blue)
    {

    }

    private void Window_Loaded_1(object sender, RoutedEventArgs e)
    {
        txtRed.Text = Convert.ToString(sldRed.Value);
        txtGreen.Text = Convert.ToString(sldGreen.Value);
        txtBlue.Text = Convert.ToString(sldBlue.Value);
    }
}

and here's my entire .xaml code.

<Grid x:Name="frmGrid" Margin="0,0,2,0">
    <Slider x:Name="sldRed" HorizontalAlignment="Left" Margin="57,10,0,0" VerticalAlignment="Top" Width="757" ValueChanged="sldChanged" ClipToBounds="True" Maximum="255" TickPlacement="BottomRight" IsSnapToTickEnabled="True" SmallChange="1" Value="1"/>
    <Slider x:Name="sldBlue" HorizontalAlignment="Left" Margin="57,76,0,0" VerticalAlignment="Top" Width="757" ValueChanged="sldChanged" ClipToBounds="True" Maximum="255" TickPlacement="BottomRight" IsSnapToTickEnabled="True" SmallChange="1" Value="1"/>
    <Slider x:Name="sldGreen" HorizontalAlignment="Left" Margin="57,45,0,0" VerticalAlignment="Top" Width="757" ValueChanged="sldChanged" ClipToBounds="True" Maximum="255" TickPlacement="BottomRight" IsSnapToTickEnabled="True" SmallChange="1" Value="1"/>
    <Label Content="Red" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
    <Label Content="Blue" HorizontalAlignment="Left" Margin="10,72,0,0" VerticalAlignment="Top"/>
    <Label Content="Green" HorizontalAlignment="Left" Margin="10,41,0,0" VerticalAlignment="Top"/>
    <TextBox x:Name="txtRed" HorizontalAlignment="Left" Height="23" Margin="819,9,0,0" TextWrapping="Wrap" Text="1" VerticalAlignment="Top" Width="41" TextChanged="inputChanged"/>
    <TextBox x:Name="txtBlue" HorizontalAlignment="Left" Height="23" Margin="819,74,0,0" TextWrapping="Wrap" Text="1" VerticalAlignment="Top" Width="41" TextChanged="inputChanged"/>
    <TextBox x:Name="txtGreen" HorizontalAlignment="Left" Height="23" Margin="819,41,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="41" TextChanged="inputChanged" Text="1"/>

</Grid>

You can see I've assigned a value to those textboxes for testing purposes.

For some reason I keep getting this error enter image description here

Which refers to these two lines.

green = Convert.ToDouble(txtGreen.Text);
blue = Convert.ToDouble(txtBlue.Text);

Note how the similar line above it works perfectly

red = Convert.ToDouble(txtRed.Text);

I'm not that experienced in C# yet, nor am I experienced in reading errors like those. If you have any idea as to why I'm getting this error and maybe provide me with a possible solution, it would be greatly appreciated.

PS: Something I just thought might be of use to you, I get this error before the program even starts up.

Here's 2 screenshots where 1 doesn't load at all, while the 2nd loads perfectly & works. enter image description here enter image description here

Upvotes: 0

Views: 718

Answers (4)

mdm20
mdm20

Reputation: 4563

The reason why this is failing is because the valuechanged event gets called when you initially create the slider in xaml and include this: Value="1". The event gets raised before the other controls are created, and thus the null exception.

WPF is built heavily upon the concept of binding, and you should utilize it as much as possible because it will make your life a lot easier. I altered your code to show you how to do it using bindings.

xaml

<Window x:Class="WpfApplication1.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"
        x:Name="TheMainWindow">
    <Grid x:Name="frmGrid" Margin="0,0,2,0">
        <Slider x:Name="sldRed" HorizontalAlignment="Left" Margin="57,10,0,0" VerticalAlignment="Top" Width="757" ClipToBounds="True" Maximum="255" TickPlacement="BottomRight" IsSnapToTickEnabled="True" 
                SmallChange="1" Value="{Binding Path=Red, ElementName=TheMainWindow, Mode=TwoWay}"/>
        <Slider x:Name="sldBlue" HorizontalAlignment="Left" Margin="57,76,0,0" VerticalAlignment="Top" Width="757" ClipToBounds="True" Maximum="255" TickPlacement="BottomRight" IsSnapToTickEnabled="True" 
                SmallChange="1" Value="{Binding Path=Blue, ElementName=TheMainWindow, Mode=TwoWay}"/>
        <Slider x:Name="sldGreen" HorizontalAlignment="Left" Margin="57,45,0,0" VerticalAlignment="Top" Width="757" ClipToBounds="True" Maximum="255" TickPlacement="BottomRight" IsSnapToTickEnabled="True"
                SmallChange="1" Value="{Binding Path=Green, ElementName=TheMainWindow, Mode=TwoWay}"/>
        <Label Content="Red" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
        <Label Content="Blue" HorizontalAlignment="Left" Margin="10,72,0,0" VerticalAlignment="Top"/>
        <Label Content="Green" HorizontalAlignment="Left" Margin="10,41,0,0" VerticalAlignment="Top"/>
        <TextBox x:Name="txtRed" HorizontalAlignment="Left" Height="23" Margin="819,9,0,0" TextWrapping="Wrap" Text="{Binding Path=Red, ElementName=TheMainWindow}" VerticalAlignment="Top" Width="41"/>
        <TextBox x:Name="txtBlue" HorizontalAlignment="Left" Height="23" Margin="819,74,0,0" TextWrapping="Wrap" Text="{Binding Path=Blue, ElementName=TheMainWindow}" VerticalAlignment="Top" Width="41" />
        <TextBox x:Name="txtGreen" HorizontalAlignment="Left" Height="23" Margin="819,41,0,0" TextWrapping="Wrap" VerticalAlignment="Top"  Text="{Binding Path=Green, ElementName=TheMainWindow}" Width="41" />
    </Grid>
</Window>

code

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private double _red = 1;
    public double Red
    {
        get { return _red; }
        set
        {
            _red = value;
            OnPropertyChanged("Red");
        }
    }

    private double _green = 1;
    public double Green
    {
        get { return _green; }
        set
        {
            _green = value;
            OnPropertyChanged("Green");
        }
    }

    private double _blue = 1;
    public double Blue
    {
        get { return _blue; }
        set
        {
            _blue = value;
            OnPropertyChanged("Blue");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Upvotes: 0

Alex Gelman
Alex Gelman

Reputation: 534

I think the problem is with your Window_Loaded_1 it changes the text value of the text boxes causing the inputChanged method to be called. try commenting out the code in Window_Loaded_1 and see if the exception still happens.

One way to solve this problem is to use binding to wire together the values of the sliders and the text boxes. Your xaml should look like this:

<Grid x:Name="frmGrid" Margin="0,0,2,0">
    <Slider x:Name="sldRed" HorizontalAlignment="Left" Margin="57,10,0,0" VerticalAlignment="Top" Width="757" ValueChanged="sldChanged" ClipToBounds="True" Maximum="255" TickPlacement="BottomRight" IsSnapToTickEnabled="True" SmallChange="1" Value="1"/>
    <Slider x:Name="sldBlue" HorizontalAlignment="Left" Margin="57,76,0,0" VerticalAlignment="Top" Width="757" ValueChanged="sldChanged" ClipToBounds="True" Maximum="255" TickPlacement="BottomRight" IsSnapToTickEnabled="True" SmallChange="1" Value="1"/>
    <Slider x:Name="sldGreen" HorizontalAlignment="Left" Margin="57,45,0,0" VerticalAlignment="Top" Width="757" ValueChanged="sldChanged" ClipToBounds="True" Maximum="255" TickPlacement="BottomRight" IsSnapToTickEnabled="True" SmallChange="1" Value="1"/>
    <Label Content="Red" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
    <Label Content="Blue" HorizontalAlignment="Left" Margin="10,72,0,0" VerticalAlignment="Top"/>
    <Label Content="Green" HorizontalAlignment="Left" Margin="10,41,0,0" VerticalAlignment="Top"/>

    <TextBox x:Name="txtRed" HorizontalAlignment="Left" Height="23" Margin="819,9,0,0" TextWrapping="Wrap" Text="{Binding ElementName=sldRed, Path=Value, Mode=TwoWay}" VerticalAlignment="Top" Width="41"/>

    <TextBox x:Name="txtBlue" HorizontalAlignment="Left" Height="23" Margin="819,74,0,0" TextWrapping="Wrap" Text="{Binding ElementName=sldBlue, Path=Value, Mode=TwoWay}" VerticalAlignment="Top" Width="41"/>

    <TextBox x:Name="txtGreen" HorizontalAlignment="Left" Height="23" Margin="819,41,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="41" Text="{Binding ElementName=sldGreen, Path=Value, Mode=TwoWay}"/>


</Grid>

and your code should look like this:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void sldChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
        red = sldRed.Value;
        green = sldGreen.Value;
        blue = sldBlue.Value;
        changeColors(red, green, blue);
    }

    void changeColors(double red, double green, double blue)
    {

    }
}

You can get rid of inputChanged and respond only to the slider changes

Upvotes: 0

Andrew
Andrew

Reputation: 835

The event handler fires when the input changes. If you hit backspace in any one of the boxes your Text is now an empty string or null. You can't turn those into doubles. Try Double.TryParse() instead of Convert.ToDouble() to determine if it's actually a parsable input like so:

private void inputChanged(object sender, TextChangedEventArgs e)
{
    double red, green, blue;

    if(Double.TryParse(txtRed.Text, out red) &&
        Double.TryParse(txtGreen.Text, out green) &&
        Double.TryParse(txtBlue.Text, out blue)) 
    {
        sldRed.Value = red;
        sldGreen.Value = green;
        sldBlue.Value = blue;
        changeColors(red, green, blue);
    }
}

If all the values in the RGB TextBoxes are valid the if statement will be true and red, green and blue will be set properly.

This is of course assuming that sldGreen and sldBlue are not null.

Upvotes: 0

Aghilas Yakoub
Aghilas Yakoub

Reputation: 28970

txtRed and txtBlue does not contain value. but txtRed contains value

You can add validation script in order to ensure that yours controls are not empty

Upvotes: 2

Related Questions