简体   繁体   中英

C# why null after casting

Hi everyone pleas help me i so confused why my code has a null after casting this is the xaml code i have

<Window.Resources>
    <Style x:Key="Menu" TargetType="{x:Type Border}">
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="Background" Value="Transparent" />
        <Setter Property="Width" Value="25" />
        <EventSetter Event="MouseLeftButtonUp" Handler="Menu_MouseLeftButtonUp" />
    </Style>
</Window.Resources>

<Grid>
    <Border Name="BorderCloseWindow" CornerRadius="0,8,0,0" 
            Style="{StaticResource Menu}">
        <Image Source="pack://application:,,,/images/icons/CloseSTD.png" />
    </Border>
</Grid>

and this the C# that handle the border

private void Menu_MouseLeftButtonUp(object sender, RoutedEventArgs e)
{
    Border b = e.Source as Border;
    if (b.Name == "BorderCloseWindow")
    {
        this.Close();
    }
}

and if i mouse button down in the border that will give error like this Object reference not set to an instance of an object. that happen in

if(b.Name == "BorderCloseWindow")

please help me why that give null? and how to repair my program so can run.

Apparently, e.Source is not of type Border .

The first thing you should fix is your cast. You are using

Border b = e.Source as Border;

which returns null if e.Source is not a Border, leading to a subsequent NullReferenceException. Since you are not checking for null afterwards, you should use a normal cast:

Border b = (Border)e.Source;

This won't fix your underlying problem, but it will make sure that

  • you get the correct exception for the underlying problem (an InvalidCastException rather than a NullReferenceException ) and
  • the error is thrown in the line that is really the cause of the problem (rather than the following if , which is entirely innocent).

Now the second thing, the source of your problem: RoutedEventsArgs.Source is not the border that you attached your event handler to (ie, it's not the control handling the event). It's the control that raised the event, which is probably the image inside the border. See the documentation of RoutedEventArgs.Source for details.

Thus, to fix this problem, use the sender instead of e.Source :

Border b = (Border)sender;

Probably sender will be Border , try to cast sender as Border first:

  Border b = sender as Border;

If it will not help, just set breakpoint within handler, than open watch window and you will see actual types of sender and e.Source .

First, that's how as behaves when the cast doesn't succeed. It is made this way so that you can easily check whether it did or not. If you wrote

Border b = (Border)e.Source;

it would throw InvalidCastException .

Second, e.Source contains the object that you actually clicked on, in this case, the Image . If you want to access the objects that is handling the event, use the sender parameter.

So your code should look like this:

private void Menu_MouseLeftButtonUp(object sender, RoutedEventArgs e)
{
    Border b = (Border)sender;
    if (b.Name == "BorderCloseWindow")
    {
        this.Close();
    }
}

Or even better, just

private void Menu_MouseLeftButtonUp(object sender, RoutedEventArgs e)
{
    this.Close();
}

This would work if set different handler method for each Control you want to handle some event for. It is much less fragile: it will still work if you change the name of the Border (you don't even need to have it named) and if you accidentally change the name of the method either in XAML or C#, you most likely get a compile-time error.

It appears e.Source is not a Border so e.Source as Border is null. Source may be another object inside the border, with the event routed to the border.

you can try to test the type of e.Source with

if (e.Source is Border)
{
}

or you could get your border object by casting sender instead of e.Source.

Change your code to look like this:

private void Menu_MouseLeftButtonUp(object sender, RoutedEventArgs e)        
{            
  System.Diagnostics.Debug.WriteLine(
    "Sender contains an object of type {0}", 
    sender.GetType());
  System.Diagnostics.Debug.WriteLine(
    "e.Source contains an object of type {0}", 
    e.Source.GetType());
}

When you trigger the event, the information you need will be written to the Output Window. You may need to make this visible using the View menu of Visual Studio. Then you will be able to see what is going on and sort it out yourself.

e.Source is an object of type image.

So you need to cast the sender as Border.

Border b = sender as Border;

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