Hãy xem xét mã này:Cách truy cập bảng phân cảnh trong tài nguyên phần tử từ XAML?
<UserControl x:Class="MyApp.MyControl"
...
xmlns:local="clr-namespace:MyApp"
DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}">
<UserControl.Template>
<ControlTemplate>
<ControlTemplate.Resources>
<Storyboard x:Key="MyStory">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="brdBase">
<SplineColorKeyFrame KeyTime="0:0:1" Value="Red"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<Border x:Name="brdBase" BorderThickness="1" BorderBrush="Cyan" Background="Black">
...
</Border>
<ControlTemplate.Triggers>
<Trigger SourceName="brdBase" Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource MyStory}"/>
</Trigger.EnterActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</UserControl.Template>
</UserControl>
Mã trên không có vấn đề gì. Bây giờ, tôi muốn giá trị key-frame ràng buộc của MyStory
đến một DP (tên SpecialColor
) của thành viên này kiểm soát như vậy:
<Storyboard x:Key="MyStory">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="brdBase">
<SplineColorKeyFrame KeyTime="0:0:1" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MyControl}}, Path=SpecialColor}"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
mà làm cho một lỗi:
có thể không đóng băng cây này timeline Storyboard cho sử dụng trên các chủ đề.
Có thể thực hiện việc này bằng mã phía sau. Nhưng làm thế nào tôi có thể làm điều đó trong XAML?
Code-Behind Aided Giải pháp:
► Bước 1: Đưa MyStory
storyboard vào brdBase
nguồn lực.
<UserControl.Template>
<ControlTemplate>
<Border x:Name="brdBase" BorderThickness="1" BorderBrush="Cyan" Background="Black">
<Border.Resources>
<Storyboard x:Key="MyStory">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="brdBase">
<SplineColorKeyFrame KeyTime="0:0:1" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MyControl}}, Path=SpecialColor}"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</Border.Resources>
...
</Border>
<ControlTemplate.Triggers>
<Trigger SourceName="brdBase" Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource MyStory}"/>
</Trigger.EnterActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</UserControl.Template>
Lỗi:Không thể tìm thấy tài nguyên có tên là 'mystory'. Tên tài nguyên phân biệt chữ hoa chữ thường.
► Bước 2: Loại bỏTrigger
trên IsMouseOver
tài sản và bắt đầu quá trình MyStory
từ mã phía sau.
<UserControl.Template>
<ControlTemplate>
<Border x:Name="brdBase" BorderThickness="1" BorderBrush="Cyan" Background="Black" MouseEnter="brdBase_MouseEnter">
<Border.Resources>
<Storyboard x:Key="MyStory">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="brdBase">
<SplineColorKeyFrame KeyTime="0:0:1" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MyControl}}, Path=SpecialColor}"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</Border.Resources>
</Border>
</ControlTemplate>
</UserControl.Template>
C# Code-Behind:
private void brdBase_MouseEnter(object sender, MouseEventArgs e)
{
Border grdRoot = (Border)this.Template.FindName("brdBase", this);
Storyboard story = grdRoot.Resources["MyStory"] as Storyboard;
story.Begin(this, this.Template);
}
► Bước 3: Các giải pháp đã được thực hiện, nhưng nó không hoạt động ở lần đầu tiên. May mắn thay, có một giải pháp cho vấn đề này. Đủ để đặt ControlTemplate
trong một Style
.
(Tôi cần Trigger
loại khác hơn EventTrigger
và phải quấn UserControl
yếu tố với ControlTemplate
.)
Cập nhật:
Ý tưởng về việc sử dụng ObjectDataProvider
thất bại.
- An ObjectDataProvider không thể sử dụng tài nguyên để cung cấp bảng phân cảnh !!! Báo cáo lỗi là:
- XamlParseException: Thiết lập thuộc tính 'System.Windows.Media.Animation.BeginStoryboard.Storyboard' ném một ngoại lệ.
- InnerException: 'System.Windows.Data.ObjectDataProvider 'không phải là một giá trị hợp lệ cho thuộc tính' Storyboard '.
- Các AssociatedControl DP luôn là null.
Đây là mã:
<UserControl.Template>
<ControlTemplate>
<ControlTemplate.Resources>
<local:StoryboardFinder x:Key="StoryboardFinder1" AssociatedControl="{Binding ElementName=brdBase}"/>
<ObjectDataProvider x:Key="dataProvider" ObjectInstance="{StaticResource StoryboardFinder1}" MethodName="Finder">
<ObjectDataProvider.MethodParameters>
<sys:String>MyStory</sys:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</ControlTemplate.Resources>
<Border x:Name="brdBase" BorderThickness="1" BorderBrush="Cyan" Background="Black">
<Border.Resources>
<Storyboard x:Key="MyStory">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="brdBase">
<SplineColorKeyFrame KeyTime="0:0:1" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MyControl}}, Path=SpecialColor}"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</Border.Resources>
...
</Border>
<ControlTemplate.Triggers>
<Trigger SourceName="brdBase" Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource dataProvider}"/>
</Trigger.EnterActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</UserControl.Template>
Lớp StoryboardFinder:
public class StoryboardFinder : DependencyObject
{
#region ________________________________________ AssociatedControl
public Control AssociatedControl
{
get { return (Control)GetValue(AssociatedControlProperty); }
set { SetValue(AssociatedControlProperty, value); }
}
public static readonly DependencyProperty AssociatedControlProperty =
DependencyProperty.Register("AssociatedControl",
typeof(Control),
typeof(StoryboardFinder),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None));
#endregion
public Storyboard Finder(string resourceName)
{
//
// Associated control is always null :(
//
return new Storyboard();
}
}
thật tuyệt, nó sẽ hoạt động không có vấn đề gì. điều duy nhất tôi có thể thấy là nó có thể kém hiệu quả hơn vì bạn không đóng băng dòng thời gian của bảng phân cảnh nữa và điều đó có nghĩa là nó không sử dụng nhiều luồng. –
Bạn nói đúng. Tôi đang tìm cách gọi phương thức 'Invoke' của' TriggerAction'. Thông qua cách này, mọi thứ cần thiết phải được thực hiện trong nội bộ. Bạn có ý tưởng gì không? (Tôi đã đánh dấu nó là 'Không thể sử dụng đoạn mã này'.) – Mimi
Trên một chế độ xem khác, trên thực tế, từ tài liệu, Begin() tự động đóng băng. Tôi quan tâm nhiều hơn về lý do tại sao Xaml không hoạt động chính xác? Tại sao bạn đang cố gắng truy cập nội dung anyways? Nó không bao giờ là ý tưởng hay, trừ khi hoàn toàn không có cách nào khác –