我有一些TextBlocks
x:Name
,我可以使用C#轻松访问此控件。不过我还有一些DoubleAnimations
x:Name
但无法访问这些,为什么会这样?
我试过这个,但它不起作用,我收到错误说Object reference not set to an instance of an object
:
//Add completed methods
DoubleAnimation da1 = (DoubleAnimation)Resources["storyboardLoad"];
da1.Completed += DoubleAnimationCompleted;
Notifications.xaml
<Window x:Class="PhotoManagement.Views.Notification"
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:PhotoManagement.Views"
mc:Ignorable="d"
Title="NotificationWindow" WindowStyle="None" AllowsTransparency="True" Background="Transparent" Width="350" SizeToContent="Height">
<Window.Resources>
<FontFamily x:Key="FontAwesome">/Fonts/#FontAwesome</FontFamily>
<SolidColorBrush x:Key="colour1" Color="#29a1d5"/>
<SolidColorBrush x:Key="colour2" Color="#248eb8"/>
<Style TargetType="StackPanel">
<Setter Property="Margin" Value="20" />
</Style>
<Style TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap" />
<Setter Property="Margin" Value="5" />
</Style>
<Style x:Key="NotificationIcon" TargetType="Border">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Background" Value="{DynamicResource colour2}" />
<Style.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontFamily" Value="{StaticResource FontAwesome}" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="28" />
<Setter Property="Padding" Value="15" />
</Style>
</Style.Resources>
</Style>
<Style x:Key="NotificationText" TargetType="Border">
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Background" Value="{DynamicResource colour1}" />
<Style.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="White" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="TextWrapping" Value="Wrap" />
</Style>
</Style.Resources>
</Style>
<Style x:Key="NotificationContainer" TargetType="Grid">
<!-- Animation -->
<Style.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<BeginStoryboard x:Name="StoryboardLoad">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(UIElement.Opacity)"
From="0.0"
To="1.0"
Duration="0:0:0.5"/>
<DoubleAnimation x:Name="storyboardLoad" Storyboard.TargetProperty="(UIElement.Opacity)"
From="1.0"
To="0.0"
Duration="0:0:1"
BeginTime="0:0:2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<RemoveStoryboard BeginStoryboardName="StoryboardLoad"/>
<RemoveStoryboard BeginStoryboardName="StoryboardFade"/>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<BeginStoryboard x:Name="StoryboardFade">
<Storyboard>
<DoubleAnimation x:Name="storyboardFade"
Storyboard.TargetProperty="(UIElement.Opacity)"
From="1.0"
To="0.0"
Duration="0:0:1"
BeginTime="0:0:2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid Style="{StaticResource NotificationContainer}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="1"
CornerRadius="0 5 5 0"
Style="{StaticResource NotificationText}">
<TextBlock Text="A request has been added!"
x:Name="NotificationText"/>
</Border>
<Border Grid.Column="0"
CornerRadius="5 0 0 5"
Style="{StaticResource NotificationIcon}">
<TextBlock Text=""
x:Name="NotificationIcon"/>
</Border>
</Grid>
<Grid.RenderTransform>
<ScaleTransform ScaleY="1" />
</Grid.RenderTransform>
</Grid>
</Window>
Notifications.xaml.cs
using System;
using System.Windows;
namespace PhotoManagement.Views
{
/// <summary>
/// Interaction logic for Notification.xaml
/// </summary>
public partial class Notification : Window
{
public Notification() : base()
{
InitializeComponent();
//Move other windows down when closed
this.Closed += this.NotificationWindowClosed;
//Get object properties
this.NotificationText.Text = "Hello";
this.NotificationIcon.Text = "G";
}
/// <summary>
/// Show the Notification and setup it's content and actions
/// </summary>
public new void Show()
{
this.Topmost = true;
this.Owner = System.Windows.Application.Current.MainWindow;
this.Closed += this.NotificationWindowClosed;
base.Show();
//Add completed methods
//Position the Notification
var workingArea = SystemParameters.WorkArea;
this.Left = (workingArea.Width - this.ActualWidth) / 2;
double top = workingArea.Bottom - this.ActualHeight - 5;
//Ensure new notifications are placed above older ones
foreach (Window window in System.Windows.Application.Current.Windows)
{
string windowName = window.GetType().Name;
if (windowName.Equals("Notification") && window != this)
{
window.Topmost = true;
top = window.Top - window.ActualHeight - 5;
}
}
this.Top = top;
}
private void ImageMouseUp(object sender,
System.Windows.Input.MouseButtonEventArgs e)
{
this.Close();
}
/// <summary>
/// Close window once animation is complete
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void DoubleAnimationCompleted(object sender, EventArgs e)
{
if (!this.IsMouseOver)
{
this.Close();
}
}
/// <summary>
/// Move the next notification down once notification has closed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void NotificationWindowClosed(object sender, EventArgs e)
{
foreach (Window window in System.Windows.Application.Current.Windows)
{
string windowName = window.GetType().Name;
if (windowName.Equals("NotificationWindow") && window != this)
{
// Adjust any windows that were above this one to drop down
if (window.Top < this.Top)
{
window.Top = window.Top + this.ActualHeight;
}
}
}
}
}
}
答案 0 :(得分:1)
创建自定义Window
或UserControl
时,会为其生成一个(部分)类,其中包含任何已命名子元素的字段。然而,这对样式和模板不起作用 - 可能因为那些可以应用于多个控件,因此名称不一定映射到单个项目(或者根本不是映射到项目)。
艰难的方式
因此,您正在寻找的动画是样式的一部分,它是您窗口中的资源。确切地说:你的风格有一系列触发器。它的第一个触发器有一个&#39;开始故事板&#39;动作,并且该动作保存了您感兴趣的故事板。它将采取一些搜索和类型转换来实现目标:
Style style = (Style)Resources["NotificationContainer"];
EventTrigger trigger = (EventTrigger)style.Triggers[0];
BeginStoryboard beginStoryboard = (BeginStoryboard)trigger.Actions[0];
Storyboard storyboard = beginStoryboard.Storyboard;
正如你所看到的那样,这很脆弱。要解决这个问题,你需要做的就是在XAML中重新排序事件触发器......
简单方法
但是为什么还要查看那个故事板呢?只需将其Completed
事件直接绑定到XAML中的事件处理程序:
<Storyboard Completed="WindowLoadedStoryboard_Completed">
...
</Storyboard>
可悲的是,由于"The event 'Completed' cannot be specified on a Target tag in a Style. Use an EventSetter instead."
错误,它无法直接运行。并且EventSetter
无效,因为Storyboard.Completed
不是路由事件...
幸运的是,您可以通过将故事板本身作为资源并在begin-storyboard动作中引用它来解决这个问题:
<Resources>
<Storyboard x:Key="WindowLoadedStoryboard" Completed="WindowLoadedStoryboard_Completed">
...
</Storyboard>
<Style ...>
...
<BeginStoryboard Storyboard="{StaticResource WindowLoadedStoryboard}" />
...
</Style>
</Resources>
顺便提一下,这也会使查看故事板更容易,更可靠。