DependencyProperty wird im Storyboard nicht getriggert



  • Hey Leute,

    Ich bitte folgendes zu beruecksichtigen: Das ganze wird in einer Windows 8 Umgebung als Windows 8 App programmiert. Das heisst, gewisse "gewohnte" WPF-Standards funktionieren hier leider nicht, deshalb kann es wohl zu merkwuerdigen Vorgehensweisen kommen.

    Folgender XAML Code in der App, soweit gekuerzt wie noetig:

    <Page
        x:Class="Zoomtest.MainPage"
        IsTabStop="false"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:Zoomtest"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid x:Name="Root" Background="{StaticResource ApplicationPageBackgroundThemeBrush}" ManipulationMode="All">
            <UserControl>
                <Grid x:Name="LayoutRoot" Background="Transparent">
                    <local:AnimatedScrollViewer  x:Name="ZoomImage" DoubleTapped="Root_DoubleTapped_1" >
                        <local:AnimatedScrollViewer.Resources>
                            <Storyboard x:Key="ScaleUpStoryboard" Storyboard.TargetName="ZoomImage">
                                <DoubleAnimation
                                    Storyboard.TargetProperty="AnimatableZoomFactor"
                                    To="2.0"
                                    From="0.0"                    
                                    Duration="00:00:00.400"/>
                            </Storyboard>
                        </local:AnimatedScrollViewer.Resources>
                    </local:AnimatedScrollViewer>
                </Grid>
            </UserControl>
        </Grid>
    </Page>
    

    Hier dazu das Control "AnimatedScrollViewer".

    public sealed class AnimatedScrollViewer : Control
        {
    
            public AnimatedScrollViewer()
            {
                this.DefaultStyleKey = typeof(AnimatedScrollViewer);
    
            }
    
            public static readonly DependencyProperty AnimatablZoomFactorProperty = DependencyProperty.Register("AnimatableZoomFactor",
            typeof(float), typeof(AnimatedScrollViewer), new PropertyMetadata(0.0f, new PropertyChangedCallback(AnimatedZoomFactorPropertyChanged)));
    
            public float AnimatableZoomFactorProperty
            {
                get { return (float)this.GetValue(AnimatablZoomFactorProperty); }
                set { this.SetValue(AnimatablZoomFactorProperty, value); }
            }
    
            private static void AnimatedZoomFactorPropertyChanged(object sender, DependencyPropertyChangedEventArgs args)
            {
                AnimatedScrollViewer cThis = sender as AnimatedScrollViewer;
                //var test = cThis.GetTemplateChild("ImageScrollViewer");
                ScrollViewer sv = cThis.GetTemplateChild("ImageScrollViewer") as ScrollViewer;
                double zoomFactor = (double)args.NewValue;
                sv.ZoomToFactor((float)zoomFactor);
            }
        }
    

    Hier nun noch das schlichte Template fuer das Control:

    <ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:Zoomtest">
    
        <Style TargetType="local:AnimatedScrollViewer">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="local:AnimatedScrollViewer">
                        <Border
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            x:Name="MyBorder">
                            <ScrollViewer x:Name="ImageScrollViewer">
                                <Image Source="Assets/SplashScreen.png"/>
                            </ScrollViewer>
                        </Border>
    
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>
    

    Ich weiss David, man koennte das DoubleTappedEvent direkt ueber nen EventTrigger an das Storyboard binden. Bloeder Weise, klassifiziert MS das scheiss Event als ein Routed, aber sobald du es an ein EventTrigger binden willst darfst du dir anhoeren das es kein RoutedEvent ist, deshalb kommt jetzt der Workaround dafuer.
    In der Main.cs

    public sealed partial class MainPage : Page
        {
            private bool isDoubleTappedZoomed;
    
            public MainPage()
            {
                this.InitializeComponent();
                this.isDoubleTappedZoomed = false;
            }
    
            /// <summary>
            /// Invoked when this page is about to be displayed in a Frame.
            /// </summary>
            /// <param name="e">Event data that describes how this page was reached.  The Parameter
            /// property is typically used to configure the page.</param>
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
            }
    
            private async void Root_DoubleTapped_1(object sender, DoubleTappedRoutedEventArgs e)
            {
                AnimatedScrollViewer scr = sender as AnimatedScrollViewer;           
                Storyboard myStoryboard = (Storyboard)scr.Resources["ScaleUpStoryboard"];
                myStoryboard.Begin();
    

    So nun die Crux an der ganzen Sache. Fliegt das DoubleTapped-Event geht er wie erwarted in den Handler rein, findet das Storyboard, fuehrt es aus aber die DP wird nicht getriggert. Nun die Frage an euch: Hat das mit dem ansteuern ueber den Code-Behind zu tuen oder hat das andere Gruende?



  • Meintest du mich? Ich sag doch gar nix ^^

    Du musst, denk ich, Storyboard.TargetName="ZoomImage" der DoubleAnimation geben, nicht dem Storyboard selber.

    Sieht man hier ganz gut:

    <Button Name="myWidthAnimatedButton"
            Height="30" Width="200" HorizontalAlignment="Left">
            A Button   
        <Button.Triggers>
            <EventTrigger RoutedEvent="Button.Click">
                <BeginStoryboard>
                    <Storyboard>           
                        <DoubleAnimation Storyboard.TargetName="myWidthAnimatedButton" // <<
                                         Storyboard.TargetProperty="Width" // <<
                                         From="200" To="300" Duration="0:0:3" />
                    </Storyboard>
               </BeginStoryboard>
           </EventTrigger>
        </Button.Triggers>
    </Button>
    

    Quelle:
    http://msdn.microsoft.com/en-us/library/system.windows.media.animation.storyboard.targetproperty.aspx



  • Klar mein ich dich :p

    Ok dann versuch ich das mal.
    Was ich mich gerade noch gefragt habe: Kommt er damit klar das ich auf nen Element verweise was in dem Template definiert ist und nicht im VisualTree der Page?

    Dank dir schonmal.



  • Welcher Verweis?
    TargetName ist "ZoomImage" (das ist direkt das control) und "AnimatableZoomFactor" ist ein Property vom ZoomImage, sehe nicht wo du in das Template hinein verweist...

    Achja, wenn du mich schon direkt an sprichst, hier mal mein Senf 😃

    public sealed class AnimatedScrollViewer : Control 
        { 
    
            public AnimatedScrollViewer() 
            { 
                this.DefaultStyleKey = typeof(AnimatedScrollViewer); // wofür ist das?
    
            } 
    
            public static readonly DependencyProperty AnimatablZoomFactorProperty = DependencyProperty.Register("AnimatableZoomFactor", 
            typeof(float), typeof(AnimatedScrollViewer), new PropertyMetadata(0.0f, new PropertyChangedCallback(AnimatedZoomFactorPropertyChanged))); 
    
            public float AnimatableZoomFactorProperty 
            { 
                get { return (float)this.GetValue(AnimatablZoomFactorProperty); } 
                set { this.SetValue(AnimatablZoomFactorProperty, value); } 
            } 
    
            private static void AnimatedZoomFactorPropertyChanged(object sender, DependencyPropertyChangedEventArgs args) 
            { 
                AnimatedScrollViewer cThis = sender as AnimatedScrollViewer; // Ich weiß nicht wie oft das in der Animation aufgerufen wird, wozu das "as" was intern eine Typprüfung macht?
                //var test = cThis.GetTemplateChild("ImageScrollViewer"); 
                ScrollViewer sv = cThis.GetTemplateChild("ImageScrollViewer") as ScrollViewer; 
                double zoomFactor = (double)args.NewValue; // wieso double welches dann danach nochmal nach float gecastet wird? Das DP ist ein float, also caste doch direkt ^^
                sv.ZoomToFactor((float)zoomFactor); 
            } 
    
    // var FTW ^^
        }
    


  • Haste Recht 😃 Hatte ne andere Version im Kopf als die die ich gepostet hab. Nun Gut, dann werd ich das mal ausprobieren und mich ggf. nochmal melden wenn es nich funktioniert.



  • David, beruhige dich bitte umgehend. Ueber var brauchen wir hier nich diskutieren 😃
    Den Rest geh ich mit. Was meinst du mit dem "as" Cast? Gleich hart casten oder was?



  • Firefighter schrieb:

    David, beruhige dich bitte umgehend.

    😃

    Firefighter schrieb:

    Was meinst du mit dem "as" Cast? Gleich hart casten oder was?

    Genau, das "as" lohnt nur wenn der Typ mal ein anderer sein kann und du dann auf null prüfen willst, caste hart dann sparst du dir Reflection.



  • Auch wieder wahr.
    Aber mal ne andere Sache. Ich hab das mal so probiert wie du gesagt hast, hat keine Aenderung gebracht.
    Wenn ich in einer Schleife die Property manuell hochzaehle dann springt er mir auch in das ChangedEvent der DP, nicht aber wenn ich das Storyboard ueber den Code starte und alles.



  • Was hat es sich mit dem "sync" an der stelle auf sich? (Root_DoubleTapped_1) Wird die Animation eventuell nicht im UI Thread getriggert?
    Gibts in VS irgendwelche Outputs?



  • David, das issen SEHR gutes Argument. Ich werde das umgehend validieren und schauen ob das einen Einfluss hat. Dank dir, hab das komplett uebersehen.



  • Sooo das async rauszunehmen hat auch keine Besserung gebracht. Das muss an dem triggern des Storyboards liegen was ich uebern Code mache, was anderes kann ich mir nich vorstellen.


Anmelden zum Antworten