[英]Why does a custom control “ImageButton” not display it's image?
我正在基於MahApps的AccentedSquareButtonStyle編寫具有突出顯示效果的圖像按鈕自定義控件。 ImageButton.xaml :
<UserControl x:Class="NQR_GUI_WPF.ImageButton"
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:local="clr-namespace:NQR_GUI_WPF"
mc:Ignorable="d" >
<Button Style="{StaticResource AccentedSquareButtonStyle}" Background="Transparent" Foreground="Transparent" BorderThickness="0" Width="24" Height="24" TouchDown="Button_TouchDown">
<Grid Background="Transparent">
<ContentControl>
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="Content" Value="{Binding Image, RelativeSource={RelativeSource TemplatedParent}}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=IsMouseOver}" Value="True" >
<Setter Property="Content" Value="{Binding HighlightedImage, RelativeSource={RelativeSource TemplatedParent}}"/>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=IsPressed}" Value="True" >
<Setter Property="Content" Value="{Binding ClickedImage, RelativeSource={RelativeSource TemplatedParent}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</Grid>
</Button>
ImageButton.xaml.cs :
namespace NQR_GUI_WPF
{
/// <summary>
/// Interaction logic for ImageButton.xaml
/// </summary>
public partial class ImageButton : UserControl
{
public static DependencyProperty ImageProperty = DependencyProperty.Register("Image", typeof(Canvas), typeof(ImageButton));
public static DependencyProperty ClickedImageProperty = DependencyProperty.Register("ClickedImage", typeof(Canvas), typeof(ImageButton));
public static DependencyProperty HighlightedImageProperty = DependencyProperty.Register("HighlightedImage", typeof(Canvas), typeof(ImageButton));
static ImageButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ImageButton), new FrameworkPropertyMetadata(typeof(ImageButton)));
}
public Canvas Image
{
get { return (Canvas)base.GetValue(ImageProperty); }
set { base.SetValue(ImageProperty, value); }
}
public Canvas ClickedImage
{
get { return (Canvas)base.GetValue(ClickedImageProperty); }
set { base.SetValue(ClickedImageProperty, value); }
}
public Canvas HighlightedImage
{
get { return (Canvas)base.GetValue(HighlightedImageProperty); }
set { base.SetValue(HighlightedImageProperty, value); }
}
private void Button_TouchDown(object sender, TouchEventArgs e)
{
Keyboard.ClearFocus();
}
}
}
示例圖標:
<Canvas x:Key="printIcon" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_printer_text" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
<Path Width="44" Height="45" Canvas.Left="16" Canvas.Top="17" Stretch="Fill" Fill="{Binding Source={x:Static prop:Settings.Default}, Path=theme, Converter={StaticResource idealForegroundConverter}}" Data="F1 M 25,27L 25,17L 51,17L 51,27L 47,27L 47,21L 29,21L 29,27L 25,27 Z M 16,28L 60,28L 60,51L 52,51L 52,46L 55,46L 55,33L 21,33L 21,46L 24,46L 24,51L 16,51L 16,28 Z M 25,39L 28,39L 28,52L 35,52L 35,59L 48,59L 48,39L 51,39L 51,62L 33,62L 25,54L 25,39 Z M 46,55L 38,55L 38,52L 46,52L 46,55 Z M 46,49L 30,49L 30,46L 46,46L 46,49 Z M 46,43L 30,43L 30,40L 46,40L 46,43 Z "/>
</Canvas>
問題在於,在MainWindow中,添加存儲在App.xaml中的圖像后,該控件為空(未顯示圖像)。
<local:ImageButton Image="{StaticResource printIcon}" HighlightedImage="{StaticResource printIconHighlighted}" ClickedImage="{StaticResource printIconClicked}" Grid.Column="1" HorizontalAlignment="Left" Height="46" Margin="36,10,0,0" VerticalAlignment="Top" Width="100"/>
我嘗試將圖像直接綁定到控件模板中,但是沒有成功(盡管在控件設計器視圖中顯示了圖像)。 為什么不顯示控制圖像?
UserControl
不是您的最佳選擇。 UserControls並非用於編寫通用WPF控件。 您可以做到,但這不是最簡單的方法。 最簡單的方法是對常規控件(通常只是ContentControl
或HeaderedContentControl
)進行子類化,然后HeaderedContentControl
編寫樣式和模板。 一旦確定了這項技術,就可以根據需要將其刪除。 通常,您可以為現有控件編寫專門的模板,但是在這種情況下,您確實需要自己的Button
子類。
我會將ImageButton
編寫為Button
的子類,並具有幾乎與您定義它們一樣的其他依賴項屬性,但是我將它們設置為Object
類型,以便使用者可以在其中填充XAML可以呈現的任何內容。 沒有理由不給他們所有可以使用的繩索。 而且我將使用Content
屬性而不是Image
屬性,因為這簡化了事情。
如果出於某種原因您需要防止非圖像內容,則可以使用比Object
更專業的內容類型,但是您沒有提及引入此限制的任何特殊原因。
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace NQR_GUI_WPF
{
/// <summary>
/// Interaction logic for ImageButton.xaml
/// </summary>
public class ImageButton : Button
{
public ImageButton()
{
TouchDown += ImageButton_TouchDown;
}
private void ImageButton_TouchDown(object sender, TouchEventArgs e)
{
Keyboard.ClearFocus();
}
#region Dependency Properties
public static DependencyProperty ClickedContentProperty = DependencyProperty.Register("ClickedContent", typeof(Object), typeof(ImageButton));
public static DependencyProperty HighlightedContentProperty = DependencyProperty.Register("HighlightedContent", typeof(Object), typeof(ImageButton));
public Object ClickedContent
{
get { return (Object)base.GetValue(ClickedContentProperty); }
set { base.SetValue(ClickedContentProperty, value); }
}
public Object HighlightedContent
{
get { return (Object)base.GetValue(HighlightedContentProperty); }
set { base.SetValue(HighlightedContentProperty, value); }
}
#endregion Dependency Properties
}
}
XAML資源字典ImageButton.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:nqrgui="clr-namespace:NQR_GUI_WPF"
>
<Style TargetType="{x:Type nqrgui:ImageButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type nqrgui:ImageButton}">
<Grid>
<ContentControl
Content="{TemplateBinding Content}"
x:Name="PART_Content"
/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter
TargetName="PART_Content"
Property="Content"
Value="{Binding HighlightedContent, RelativeSource={RelativeSource TemplatedParent}}"
/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter
TargetName="PART_Content"
Property="Content"
Value="{Binding ClickedContent, RelativeSource={RelativeSource TemplatedParent}}"
/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
這是您的使用方式:
<Window
...
xmlns:nqrgui="clr-namespace:NQR_GUI_WPF"
...
>
<!-- Or better yet, merge ImageButton.xaml in App.xaml so everybody can see it -->
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ImageButton.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
...
<!-- As noted, Content, HighlightedContent, and ClickedContent
can be images -- or also paths, text, ANYTHING XAML can render.
-->
<nqrgui:ImageButton
Content="Content"
HighlightedContent="Highlighted"
ClickedContent="Clicked"
/>
而且您真的可以對內容絕對發瘋:
<!-- Don't try this in a UI anybody will have to use! -->
<nqrgui:ImageButton
Content="Content"
ClickedContent="Clicked"
>
<nqrgui:ImageButton.HighlightedContent>
<StackPanel Orientation="Horizontal">
<Border
BorderBrush="Gray"
Background="GhostWhite"
BorderThickness="1">
<Path
Width="20"
Height="20"
Stroke="Black"
StrokeThickness="2"
Data="M 0,0 L 20,20 M 0,20 L 20,0"
Margin="2"
/>
</Border>
<nqrgui:ImageButton
Content="LOL"
ClickedContent="Don't Click Me, Bro!"
HighlightedContent="I heard you like buttons"
/>
</StackPanel>
</nqrgui:ImageButton.HighlightedContent>
</nqrgui:ImageButton>
您使用的TemplateParent
錯誤
代替這個
{Binding Image, RelativeSource={RelativeSource TemplatedParent}}
應該是這樣的
{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=ImageButton}, Path=Image}
我在下面做了這樣的事情,
<Controls:MetroWindow.Resources>
<ImageBrush Stretch="Fill" x:Key="CloseImage" ImageSource="../images/Close.png" />
<ImageBrush x:Key="CloseImageRed" ImageSource="../images/CloseRed.jpg" />
</Controls:MetroWindow.Resources>
<Button>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="{StaticResource CloseImageRed}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
RecognizesAccessKey="True"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource CloseImage}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
看一看。
您正在將UserControl.Content
設置為自定義的Button,我想您要設置的是UserControl.ContentTemplate
。
從.Content
內部,沒有要綁定的“ TemplatedParent”。 但是,如果這是Template
,則TemplatedParent
將指向為其定義模板的UserControl
。 在這種情況下,它將引用您的ImageButton UserControl,它將正確地授予您訪問Image
屬性的權限。
<UserControl ..>
<UserControl.ContentTemplate>
<ControlTemplate>
<!-- TemplatedParent bindings should refer to UserControl from here -->
<Button ... />
</ControlTemplate>
</UserControl.ContentTemplate>
</UserControl>
這也使您可以編寫類似
<local:ImageButton Content="Some Text" />
而不用包含“某些文本”的Text元素完全替換Button XAML代碼
例如,您現在擁有的將呈現為
<UserControl>
<Button /> <!-- Button is .Content, and can be replaced by XAML using the control -->
</UserControl>
如果是ContentTemplate,它將呈現為
<UserControl>
<Button> <!-- Button is ContentTemplate, so wraps any content given by external XAML -->
<Content />
</Button>
</UserControl>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.