在下面的示例中,我有一个UserControl,该控件设置一个图像源以在其构造函数中显示,然后使用其Loaded事件处理程序设置另一个图像源。当我将此控件用作通过样式和/或样式触发器指定的OpacityMask用作VisualBrush的Visual时,我再也看不到调用了Loaded事件处理程序。
下面的代码中有四个用法示例。
首先,用户控件是单独使用的(我们看到了Loaded事件处理程序的结果)。这表明控件本身按说明工作。
第二,在最接近我的实际用例的简单示例中,在用于设置OpacityMask的Style中的Trigger中使用了它(看不到Loaded事件的结果)。
第三,直接指定OpacityMask(可以看到Loaded事件的结果)。这表明该控件可以用作掩码,并且仍然可以调用Loaded事件处理程序。
第四,OpacityMask是通过样式指定的,但没有触发器(并且看不到加载的结果)。
在样式中使用此控件时,为什么不触发Loaded事件?我该怎么办才能发火?
一些评论:
以类似于MediaElement的LoadedBehavior的方式使用Loaded事件,以根据多个依赖项属性的值将控件置于初始状态。
我确实确认了在我看不到结果的情况下,实际上没有调用Loaded事件处理程序。
实际用例在ItemsControl中应用了一组复杂的样式和模板。重写以直接指定OpacityMask是不切实际的(特别是触发器提供了一些重要的功能)。
我们可以将此UserControl用作任何其他控件(例如TextBox)上的遮罩,因此我们不能期望被遮罩的控件执行任何操作来告知控件已加载。
出于我们的目的,Initialized事件触发得太早(特别是,尚未设置通过XAML设置的任何属性,实际上,我们需要设置这些属性)。
关于VisualBrush.Visual的评论似乎很相关。但是,我认为在样式中使用布局时必须在控件上运行布局-否则,将不会显示任何内容,对吧?
但是,根UIElement本质上与系统的其余部分是隔离的。样式,情节提要和外部布局(由父母在其上应用画笔指定)无法渗透到此边界。因此,您应该显式指定根UIElement的大小,因为它的唯一父级是VisualBrush,因此它无法自动将自身调整为要绘制的区域的大小。有关Windows Presentation Foundation(WPF)中的布局的更多信息,请参见布局。
UserControl的XAML:
<UserControl x:Class="WpfApplication1.UserControl1"
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:WpfApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Loaded="UserControl1_OnLoaded">
<Image Width="791" Height="119">
<Image.Style>
<Style TargetType="Image">
<Setter Property="Source">
<Setter.Value>
<Binding Path="CurrentImagePath" RelativeSource="{RelativeSource AncestorType=local:UserControl1}" />
</Setter.Value>
</Setter>
</Style>
</Image.Style>
</Image>
</UserControl>
和后面的UserControl代码:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
CurrentImagePath = "pack://application:,,,/Resources/SampSeq_0000.png";
}
public string CurrentImagePath
{
get { return (string)GetValue(CurrentImagePathProperty); }
protected set { SetValue(CurrentImagePathProperty, value); }
}
public static readonly DependencyProperty CurrentImagePathProperty =
DependencyProperty.Register("CurrentImagePath", typeof(string), typeof(UserControl1),
new UIPropertyMetadata(string.Empty, null, null));
private void UserControl1_OnLoaded(object sender, RoutedEventArgs e)
{
CurrentImagePath = "pack://application:,,,/Resources/SampSeq_0002.png";
}
}
最后四个示例使用:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="750" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- usage of the control by itself -->
<local:UserControl1 Grid.Row="0" />
<CheckBox Grid.Row="1" x:Name="checkBox" Content="mask?" IsChecked="False"/>
<!-- usage of the control as a triggered opacity mask -->
<Rectangle Grid.Row="2" Width="791" Height="119" Fill="BlueViolet">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Setter Property="OpacityMask" Value="{x:Null}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsChecked, ElementName=checkBox}" Value="True">
<Setter Property="OpacityMask">
<Setter.Value>
<VisualBrush>
<VisualBrush.Visual>
<local:UserControl1 />
</VisualBrush.Visual>
</VisualBrush>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
<!-- usage of the control as a directly specified OpacityMask -->
<Rectangle Grid.Row="3" Width="791" Height="119" Fill="OrangeRed">
<Rectangle.OpacityMask>
<VisualBrush>
<VisualBrush.Visual>
<local:UserControl1 />
</VisualBrush.Visual>
</VisualBrush>
</Rectangle.OpacityMask>
</Rectangle>
<!-- usage of the control in OpacityMask applied with a style but without triggers-->
<Rectangle Grid.Row="4" Width="791" Height="119" Fill="DarkGreen">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Setter Property="OpacityMask">
<Setter.Value>
<VisualBrush>
<VisualBrush.Visual>
<local:UserControl1 />
</VisualBrush.Visual>
</VisualBrush>
</Setter.Value>
</Setter>
</Style>
</Rectangle.Style>
</Rectangle>
</Grid>
</Window>
我使用了两个示例图像: