Самодельная ImageButton, встроенная в UserControl, встроенная в другой UserControl, не отображающая изображение - PullRequest
0 голосов
/ 22 июня 2011

Я написал базовый элемент управления ImageButton, который происходит от Button. Вот XAML для стиля кнопки в 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>

Как видите, шаблон состоит из кнопки с элементом управления изображением. Вот как выглядит код для класса:

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
        DefaultStyleKeyProperty.OverrideMetadata( typeof( ImageButton ), new FrameworkPropertyMetadata( typeof( ImageButton ) ) );
    }
}

Я знаю, что этот элемент управления работает, так как я написал тестовую программу, которая загружает JPEG с жесткого диска, создает объект BitmapImage из потока файлов и устанавливает свойство Source ImageButton для нового объекта BitmapImage. Изображение отображается, и пользователь может щелкнуть по нему.

У меня есть UserControl, в который я встроил экземпляр ImageButton. Вот XAML для этого элемента управления.

<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>

Код для Channel очень длинный и запутанный, поэтому я не могу включить все это. Канал имеет метод с именем DisplayRead, который принимает объект с именем «read» типа DisplayRead (разные пространства имен), который считывается из базы данных. Этот объект содержит два файла JPEG, которые хранятся в виде байтовых массивов. Код в DisplayRead решает, какой из двух JPEG-файлов отображать в ImageButton, а затем выполняет для этого следующий код:

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

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

Код в DisplayImage просто хранит данные, которые будут отображаться, как изображения выше, в свойствах CLR. После сохранения этих значений он использует объект Channel Dispatcher для планирования запуска метода UpdateChanel, который фактически устанавливает свойства для отображения данных, хранящихся в свойствах CLR. Вот выдержка из 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;

Из приведенного выше фрагмента изображение, помещенное в свойство Source CarImage, не отображается, а изображение, помещенное в PlateCloseupImageButton, действительно отображается.

Я использовал SNOOP для обхода визуального дерева, и это показывает, что свойство Source обоих ImageButtons установлено, но свойство source встроенного изображения CarImage не установлено, но установлен Source для PlateCloseupImageButton. Тем не менее, я добавил некоторый код в сеттер в свойстве Source ImageButton, чтобы увидеть, действительно ли свойство источника Image имеет значение null. Не было; он был установлен точно так, как я ожидал.

Это сбило меня с толку. Я понятия не имею, почему встроенная в канал ImageButton не отображает свое изображение. Единственные различия, которые мне удалось найти, заключаются в том, что:

  1. CarImage встраивается дальше вниз по дереву визуалов. Не должно иметь значения.

  2. Тип источника для PlateImage - BitmapImage, а для PlateCloseupImageButton - CachedBitmap.

Любая помощь будет принята с благодарностью.

Tony

1 Ответ

0 голосов
/ 24 июня 2011

ОК, я нашел ответ на этот вопрос с помощью моего руководителя команды. Источник проблемы в следующем коде:

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

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

Использование оператора является причиной проблемы. Оператор using закрыл MemoryStream до того, как BitmapImage сможет прочитать из него изображение. Оказывается, байты для BitmapImage не читаются из потока, пока он не отобразится. Когда я удалил оператор using, все работает.

Tony

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...