简体   繁体   中英

WPF Slider control (NullReferenceException)

I'm trying to display the value of a slider control in a TextBlock. However I keep getting a NullRerferenceException when I try to load the dialog.

public partial class GeneralSettingsDialog : Window
{

    public GeneralSettingsDialog()
    {  
        InitializeComponent();
    }

    private void DistSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
        DistTextBlock.Text = DistSlider.Value.ToString();
    }
}

XAML:

        <TabItem Header="Miscellaneous" Name="tabItem1" Background="#FFF0F0F0">
            <Grid Height="230" Background="#FFF0F0F0">
                <TextBlock Height="23" HorizontalAlignment="Left" Margin="13,13,0,0" Name="textBlock1" Text="Spacing" VerticalAlignment="Top" />
                <Slider Height="23" HorizontalAlignment="Left" IsSnapToTickEnabled="True" TickPlacement="BottomRight" Margin="13,35,0,0" Name="DistSlider" VerticalAlignment="Top" Width="100" Interval="1" Maximum="50" Minimum="1" ValueChanged="DistSlider_ValueChanged" />
                <TextBlock Height="23" HorizontalAlignment="Left" Margin="111,35,0,0" Name="DistTextBlock" Text="TextBlock" VerticalAlignment="Top" />

            </Grid>
        </TabItem>

Not exactly sure why your way isn't working, I guess the controls are not fully initialized when the first value changed event is thrown. But you can do it that way directly in xaml without any code behind:

in TextBlock bind directly to the slider's current value and remove the value changed event handler:

 Text="{Binding ElementName=DistSlider, Path=Value}"

PS:

When you attach to the slider's value changed event in codebehind after InitializeComponent() your approach should also work fine:

public MainWindow()
{
  InitializeComponent();
  DistSlider.ValueChanged +=new RoutedPropertyChangedEventHandler<double>(DistSlider_ValueChanged);
}

private void DistSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
    DistTextBlock.Text = DistSlider.Value.ToString();
}

In your XAML you have the TextBlock DistTextBlock defined after DistSlider . When the XAML is loaded for the first time it will fire the ValueChanged handler and DistTextBlock will be null. You can protect against this in a few ways:

// 1. Naive, but least changes to your code
if (DistTextBlock != null)
{
    DistTextBlock.Text = DistSlider.Value.ToString();
}

There is @SvenG's excellent suggestion , which moves the logic to the XAML (no need for a ValueChanged handler):

<TextBlock Text="{Binding Value, ElementName=DistSlider}" ... />

Lastly you could use a ViewModel (or any data context supporting INotifyPropertyChanged ) to handle the passing to and from of the value.

The important part of using the binding is it allows you to put any string formatting right alongside its usage in the XAML (say, if this slider was for a currency amount):

<TextBlock Text="{Binding Value, ElementName=DistSlider, StringFormat={}{0:C}}"

The last bonus of using a binding is coming out in .Net Framework 4.5, which allows you to specify a time delay prior to the binding updating its source . This would allow your GUI to seem more reactive if the binding is used in expensive operations.

<Slider Value="{Binding DollarAmount, Delay=50}" ... />
<TextBlock Text="{Binding DollarAmount, StringFormat={}{0:C}}" ... />

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM