Я написал базовый элемент управления 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 не отображает свое изображение. Единственные различия, которые мне удалось найти, заключаются в том, что:
CarImage встраивается дальше вниз по дереву визуалов. Не должно иметь значения.
Тип источника для PlateImage - BitmapImage, а для PlateCloseupImageButton - CachedBitmap.
Любая помощь будет принята с благодарностью.
Tony