WPF:控件模板的名称范围问题
我正在尝试为 System.Windows.Controls.Button 编写 ControlTemplate,但我一直遇到附加行为中的动画问题。具体来说,将鼠标悬停在按钮上会产生运行时错误:
InvalidOperationException 是 未处理:没有适用的名称范围 存在用于解析名称“myBrush”。
当调用 sb.Begin() 时,这种情况会在“ButtonVisualBehavior.cs”文件中发生(请参阅下面发布的代码)。不管怎样,我已经尝试了一切我能想象的方法来解决这个问题,但我仍然遇到麻烦。任何帮助将不胜感激!
代码如下:
ButtonStyleV.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication4">
<Style TargetType="{x:Type Button}" x:Key="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<ControlTemplate.Resources>
<Storyboard x:Key="ButtonStoryboardKey">
<ColorAnimation Storyboard.TargetName="myBrush"
Storyboard.TargetProperty="Color"
From="White"
To="Black"
Duration="0:0:1.0"
RepeatBehavior="Forever"
AutoReverse="True" />
</Storyboard>
</ControlTemplate.Resources>
<Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
<Rectangle x:Name="ButtonRect"
Stroke="{x:Null}" Opacity="1"
Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Rectangle.Fill>
<SolidColorBrush x:Name="myBrush" />
</Rectangle.Fill>
</Rectangle>
<ContentPresenter x:Name="ButtonContentPresenter"
Content="{TemplateBinding Button.Content}"
ContentTemplate="{TemplateBinding Button.ContentTemplate}"
HorizontalAlignment="Center" VerticalAlignment="Center">
</ContentPresenter>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="local:ButtonVisualBehaviorV.IsBehaviorAttached" Value="True" />
</Style>
</ResourceDictionary>
ButtonVisualBehavior.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Input;
using System.Windows.Media.Animation;
namespace WpfApplication4
{
class ButtonVisualBehaviorV
{
public static bool GetIsBehaviorAttached(DependencyObject obj)
{
return (bool)obj.GetValue(IsBehaviorAttachedProperty);
}
public static void SetIsBehaviorAttached(DependencyObject obj, bool value)
{
obj.SetValue(IsBehaviorAttachedProperty, value);
}
// Using a DependencyProperty as the backing store for IsBehaviorAttached.
// This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsBehaviorAttachedProperty =
DependencyProperty.RegisterAttached(
"IsBehaviorAttached",
typeof(bool),
typeof(ButtonVisualBehaviorV),
new UIPropertyMetadata(false, OnIsBehaviorAttachedChanged));
private static void OnIsBehaviorAttachedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Button button = d as Button;
if ((button == null) || ((bool)e.NewValue == false))
return;
if (((bool)e.NewValue) == true)
{
button.MouseEnter += Button_MouseEnter;
button.MouseLeave += Button_MouseLeave;
}
else
{
button.MouseEnter -= Button_MouseEnter;
button.MouseLeave -= Button_MouseLeave;
}
}
private static void Button_MouseEnter(object sender, MouseEventArgs e)
{
Button button = sender as Button;
Rectangle buttonRectangle = button.Template.FindName("ButtonRect", button) as Rectangle;
Storyboard sb = buttonRectangle.FindResource("ButtonStoryboardKey") as Storyboard;
sb.Begin();
}
private static void Button_MouseLeave(object sender, MouseEventArgs e)
{
Button button = sender as Button;
Rectangle buttonRectangle = button.Template.FindName("ButtonRect", button) as Rectangle;
Storyboard sb = buttonRectangle.FindResource("ButtonStoryboardKey") as Storyboard;
sb.Begin();
}
}
}
Window2.xaml:
<Window x:Class="WpfApplication4.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication4"
Title="Window2" Height="300" Width="300">
<Grid>
<Button Background="Green" Content="Button" Height="30" HorizontalAlignment="Left" Margin="120,138,0,0" VerticalAlignment="Top" Width="75" />
</Grid>
</Window>
最后,app.xaml:
<Application x:Class="WpfApplication4.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication4"
StartupUri="Window2.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Troubleshooting/ButtonStyleV.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
谢谢!
安德鲁
I'm trying to write a ControlTemplate for a System.Windows.Controls.Button, but I keep running into trouble with an animation that I have in an attached behavior. Specifically, mousing over the button produces the runtime error:
InvalidOperationException was
unhandled: No applicable name scope
exists to resolve the name 'myBrush'.
This happens in the 'ButtonVisualBehavior.cs' file when sb.Begin() is called (see code posted below). Anyway, I've tried everything I can imagine to fix this, and I'm still having trouble. Any help will be greatly appreciated!
Here's the code:
ButtonStyleV.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication4">
<Style TargetType="{x:Type Button}" x:Key="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<ControlTemplate.Resources>
<Storyboard x:Key="ButtonStoryboardKey">
<ColorAnimation Storyboard.TargetName="myBrush"
Storyboard.TargetProperty="Color"
From="White"
To="Black"
Duration="0:0:1.0"
RepeatBehavior="Forever"
AutoReverse="True" />
</Storyboard>
</ControlTemplate.Resources>
<Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
<Rectangle x:Name="ButtonRect"
Stroke="{x:Null}" Opacity="1"
Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Rectangle.Fill>
<SolidColorBrush x:Name="myBrush" />
</Rectangle.Fill>
</Rectangle>
<ContentPresenter x:Name="ButtonContentPresenter"
Content="{TemplateBinding Button.Content}"
ContentTemplate="{TemplateBinding Button.ContentTemplate}"
HorizontalAlignment="Center" VerticalAlignment="Center">
</ContentPresenter>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="local:ButtonVisualBehaviorV.IsBehaviorAttached" Value="True" />
</Style>
</ResourceDictionary>
ButtonVisualBehavior.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Input;
using System.Windows.Media.Animation;
namespace WpfApplication4
{
class ButtonVisualBehaviorV
{
public static bool GetIsBehaviorAttached(DependencyObject obj)
{
return (bool)obj.GetValue(IsBehaviorAttachedProperty);
}
public static void SetIsBehaviorAttached(DependencyObject obj, bool value)
{
obj.SetValue(IsBehaviorAttachedProperty, value);
}
// Using a DependencyProperty as the backing store for IsBehaviorAttached.
// This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsBehaviorAttachedProperty =
DependencyProperty.RegisterAttached(
"IsBehaviorAttached",
typeof(bool),
typeof(ButtonVisualBehaviorV),
new UIPropertyMetadata(false, OnIsBehaviorAttachedChanged));
private static void OnIsBehaviorAttachedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Button button = d as Button;
if ((button == null) || ((bool)e.NewValue == false))
return;
if (((bool)e.NewValue) == true)
{
button.MouseEnter += Button_MouseEnter;
button.MouseLeave += Button_MouseLeave;
}
else
{
button.MouseEnter -= Button_MouseEnter;
button.MouseLeave -= Button_MouseLeave;
}
}
private static void Button_MouseEnter(object sender, MouseEventArgs e)
{
Button button = sender as Button;
Rectangle buttonRectangle = button.Template.FindName("ButtonRect", button) as Rectangle;
Storyboard sb = buttonRectangle.FindResource("ButtonStoryboardKey") as Storyboard;
sb.Begin();
}
private static void Button_MouseLeave(object sender, MouseEventArgs e)
{
Button button = sender as Button;
Rectangle buttonRectangle = button.Template.FindName("ButtonRect", button) as Rectangle;
Storyboard sb = buttonRectangle.FindResource("ButtonStoryboardKey") as Storyboard;
sb.Begin();
}
}
}
Window2.xaml:
<Window x:Class="WpfApplication4.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication4"
Title="Window2" Height="300" Width="300">
<Grid>
<Button Background="Green" Content="Button" Height="30" HorizontalAlignment="Left" Margin="120,138,0,0" VerticalAlignment="Top" Width="75" />
</Grid>
</Window>
and finally, app.xaml:
<Application x:Class="WpfApplication4.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication4"
StartupUri="Window2.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Troubleshooting/ButtonStyleV.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Thanks!
Andrew
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您似乎已经解决了眼前的问题,但也许您很欣赏如何以更少的努力完成同样的事情,并且仅在 XAML 中使用
VisualStateManager
即可,如下所示:You seemed to have solved your immediate problem but perhaps you appreciate how you can accomplish the same thing with a lot less effort and in XAML only by using the
VisualStateManager
like this: