开发者

Homemade ImageButton embedded in a UserControl, embedded in another UserControl, not displaying an image

开发者 https://www.devze.com 2023-03-14 14:24 出处:网络
I\'ve written a basic ImageButton control, which descends from Button.Here\'s the XAML for the button\'s style in Generic.XAML:

I've written a basic ImageButton control, which descends from Button. Here's the XAML for the button's style in Generic.XAML:

<Style TargetType="{x:Type local:ImageButton}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:ImageButton}">
                <Button Background="{TemplateBinding Background}" 
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        Clip="{TemplateBinding Clip}" 
                        ClipToBounds="{TemplateBinding ClipToBounds}" 
                        FlowDirection="{TemplateBinding FlowDirection}"
                        Height="{TemplateBinding Height}"
                        HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
                        HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                        Margin="{TemplateBinding Margin}"
                        MaxHeight="{TemplateBinding MaxHeight}"
                        MaxWidth="{TemplateBinding MaxWidth}"
                        MinHeight="{TemplateBinding MinHeight}"
                        MinWidth="{TemplateBinding MinWidth}"
                        Opacity="{TemplateBinding Opacity}"
                        OpacityMask="{TemplateBinding OpacityMask}"
                        Padding="{TemplateBinding Padding}"
                        SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                        ToolTip="{TemplateBinding ToolTip}"
                        VerticalAlignment="{TemplateBinding VerticalAlignment}"
                        VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                        Visibility="{TemplateBinding Visibility}"
                        Width="{TemplateBinding Width}" >
                    <Image Name="Image" 
                           HorizontalAlignment="Stretch"
                           SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                           Source="{TemplateBinding Source}" 
                           Stretch="Uniform" 
                           VerticalAlignment="Stretch" />
                </Button>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

As you can see, the Template consists of a button with an Image control in it. Here's what the code-behind for the class looks like:

public partial class ImageButton : Button {

    public static readonly DependencyProperty SourceProperty =
        DependencyProperty.Register( "Source", typeof( ImageSource ), typeof( ImageButton ),
                                     new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.AffectsMeasure |
                                                                          FrameworkPropertyMetadataOptions.AffectsParentMeasure |
                                                                          FrameworkPropertyMetadataOptions.AffectsRender ) );

    public ImageSource Source {
        get { return (ImageSource) GetValue( SourceProperty ); }
        set { SetValue( SourceProperty, value ); }
    }

    public ImageButton() : base() {}

    static ImageButton() {
        // Tell this control to use our default style property in Generic.xaml
        Defau开发者_StackOverflow社区ltStyleKeyProperty.OverrideMetadata( typeof( ImageButton ), new FrameworkPropertyMetadata( typeof( ImageButton ) ) );
    }
}

I know this control works as I've written a test program that loads a JPEG from the hard drive, creates a BitmapImage object from the file stream, and sets the ImageButton's Source property to the new BitmapImage object. The image displays & the user can click on it.

I have a UserControl in which I've embedded an instance of the ImageButton. Here's the XAML for that control.

<UserControl x:Class="CarSystem.CustomControls.Channel"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:cs="clr-namespace:CarSystem.CustomControls"
         mc:Ignorable="d" 
         d:DesignHeight="211" d:DesignWidth="281">

<Grid>
    <cs:ImageButton BorderBrush="Black"
                    BorderThickness="1" 
                    Click="CarImage_Click" 
                    HorizontalAlignment="Stretch"
                    HorizontalContentAlignment="Stretch"
                    x:Name="CarImage"
                    VerticalAlignment="Stretch" 
                    VerticalContentAlignment="Stretch" />
    <Canvas Name="ChannelCanvas">
        <ComboBox Background="{x:Null}"
                  FontSize="18" 
                  Foreground="Black" 
                  HorizontalContentAlignment="Center" 
                  Margin="5" 
                  MinHeight="25" 
                  Name="CameraPicker" 
                  Panel.ZIndex="1" 
                  SelectionChanged="Picker_SelectionChanged"
                  VerticalAlignment="Top" 
                  Visibility="Hidden" />
        <Rectangle Fill="{x:Null}"
                   Margin="5" 
                   MinHeight="25" 
                   Name="NameRectangle"
                   RadiusX="2" 
                   RadiusY="2"  
                   Stroke="Black" 
                   Visibility="Hidden" />
        <TextBlock FontSize="18" 
                   Foreground="Black" 
                   MinHeight="25" 
                   Name="CameraName"
                   Visibility="Hidden" />
    </Canvas>
</Grid>

The code-behind for Channel is very long and convoluted, so I can't include all of it. Channel has a method called DisplayRead which takes an object called "read" of type DisplayRead (different namespaces), which is read from a database. This object contains two JPEGs, stored as byte arrays. The code in DisplayRead decides which of the two JPEGs to display in the ImageButton and then executes the following code to do so:

if ( read.OverviewImage != null ) {
    OverviewImage = new BitmapImage();

    using ( MemoryStream memoryStream = new MemoryStream( read.OverviewImage.ImageBytes ) ) {
        OverviewImage.BeginInit();
        OverviewImage.StreamSource = memoryStream;
        OverviewImage.EndInit();
    }
}

The code in DisplayImage just stores data to be displayed, like the images above, in CLR properties. After storing these values, it uses the Channel's Dispatcher object to schedule the UpdateChanel method to run, which actually sets the properties to display the data stored in the CLR properties. Here's an excerpt from UpdateChannel:

// CarImage is an instance of ImageButton in the Channel control
if ( CarImage != null && OverviewImage != null ) {
    CarImage.Source = image;
}

// PlateCloseupImageButton is an instance of ImageButton on the UserControl that is this Channel's parent.
// PlateCloseupImage is another CLR property.  It holds a BitmapSource that contains a rectangle taken from
// another JPEG in the Read.
PlateCloseupImageButton.Source = PlateCloseupImage;

From the above snippet, the image put into CarImage's Source property is not displaying, but the one put into PlateCloseupImageButton does display.

I've used SNOOP to walk the visual tree and that shows the Source Property of both ImageButtons are set, but the source property of CarImage's embedded Image is not set, but the PlateCloseupImageButton's Source is set. However, I added some code to the setter in the ImageButton's Source property to see if the Image's source property really was null. It wasn't; it was set to exactly what I expected it to be set to.

This has me baffled. I have no idea why the ImageButton embedded in the Channel isn't displaying its image. The only differences I've been able to find are that:

  1. CarImage is embedded further down the Visual Tree. Shouldn't make a difference.

  2. The type of the Source for PlateImage is BitmapImage, while that of PlateCloseupImageButton is CachedBitmap.

Any help would be greatly appreciated.

Tony


OK, I found the answer to this one, with the help of my team lead. The source of the problem is in the following code:

if ( read.OverviewImage != null ) {
    OverviewImage = new BitmapImage();

    using ( MemoryStream memoryStream = new MemoryStream( read.OverviewImage.ImageBytes ) ) {
        OverviewImage.BeginInit();
        OverviewImage.StreamSource = memoryStream;
        OverviewImage.EndInit();
    }
} 

The using statement is the cause of the problem. The using statement closed the MemoryStream before the BitmapImage could read the image from it. Turns out the bytes for the BitmapImage aren't read from the stream until it is displayed. When I removed the using statement, everything works.

Tony

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号