WinRT自定义控件:OnApplyTemplate似乎不是在合适的时间调用

时间:2014-09-17 10:45:55

标签: windows-runtime windows-8.1 windows-phone-8.1

我编写了一个自定义控件,旨在在加载实际图像时显示占位符图像。它是用通用应用程序编写的。 这是我控制的代码:

public class DeferredImage : Control
{
    public static readonly DependencyProperty PlaceholderSourceProperty =
        DependencyProperty.Register("PlaceholderSource", typeof(ImageSource), typeof(DeferredImage), new PropertyMetadata(null, OnPlaceholderSourcePropertyChanged));

    public static readonly DependencyProperty SourceProperty =
        DependencyProperty.Register("Source", typeof(ImageSource), typeof(DeferredImage), new PropertyMetadata(null, OnSourcePropertyChanged));

    public static readonly DependencyProperty StretchProperty =
        DependencyProperty.Register("Stretch", typeof(Stretch), typeof(DeferredImage), new PropertyMetadata(Stretch.Uniform, OnStretchPropertyChanged));

    private const string PlaceholderImageName = "PlaceholderImage";
    private const string ActualImageName = "ActualImage";

    private const string DefaultStateName = "DefaultState";
    private const string ActualStateName = "ActualState";

    private Image _placeholderImage;

    private Image _actualImage;

    public ImageSource PlaceholderSource
    {
        get { return (ImageSource)GetValue(PlaceholderSourceProperty); }
        set { SetValue(PlaceholderSourceProperty, value); }
    }

    public ImageSource Source
    {
        get { return (ImageSource)GetValue(SourceProperty); }
        set { SetValue(SourceProperty, value); }
    }

    public Stretch Stretch
    {
        get { return (Stretch)GetValue(StretchProperty); }
        set { SetValue(StretchProperty, value); }
    }

    public DeferredImage()
    {
        DefaultStyleKey = typeof(DeferredImage);
    }

    protected override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        _placeholderImage = GetTemplateChild(PlaceholderImageName) as Image;
        _actualImage = GetTemplateChild(ActualImageName) as Image;

        if (_placeholderImage != null)
        {
            _placeholderImage.Source = PlaceholderSource;
            _placeholderImage.Stretch = Stretch;
        }

        if (_actualImage != null)
        {
            _actualImage.Source = Source;
            _actualImage.Stretch = Stretch;
        }
    }

    private static void OnPlaceholderSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var defferedImage = d as DeferredImage;
        if (defferedImage != null && defferedImage._placeholderImage != null)
        {
            defferedImage._placeholderImage.Source = (ImageSource)e.NewValue;
        }
    }

    private static void OnSourcePropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        var defferedImage = o as DeferredImage;
        if (defferedImage != null && defferedImage._actualImage != null)
        {
            var newImageSource = (ImageSource)e.NewValue;
            defferedImage._actualImage.Source = newImageSource;
            VisualStateManager.GoToState(defferedImage, newImageSource == null ? DefaultStateName : ActualStateName, false);
        }
    }

    private static void OnStretchPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var instance = d as DeferredImage;
        if (instance != null)
        {
            if (instance._placeholderImage != null)
                instance._placeholderImage.Stretch = (Stretch)e.NewValue;
            if (instance._actualImage != null)
                instance._actualImage.Stretch = (Stretch)e.NewValue;
        }
    }
}

以下是控件模板的代码:

<Style TargetType="controls:DeferredImage">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="controls:DeferredImage">
                <Grid>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="DefaultState">
                                <Storyboard>
                                    <DoubleAnimation Duration="0:0:0.3"
                                                     To="1"
                                                     Storyboard.TargetName="PlaceholderImage"
                                                     Storyboard.TargetProperty="Opacity" />
                                    <DoubleAnimation Duration="0:0:0.3"
                                                     To="0"
                                                     Storyboard.TargetName="ActualImage"
                                                     Storyboard.TargetProperty="Opacity" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="ActualState">
                                <Storyboard>
                                    <DoubleAnimation Duration="0:0:0.3"
                                                     To="0"
                                                     Storyboard.TargetName="PlaceholderImage"
                                                     Storyboard.TargetProperty="Opacity" />
                                    <DoubleAnimation Duration="0:0:0.3"
                                                     To="1"
                                                     Storyboard.TargetName="ActualImage"
                                                     Storyboard.TargetProperty="Opacity" />
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Image Name="PlaceholderImage"
                           Opacity="1"
                           Canvas.ZIndex="-1" />
                    <Image Name="ActualImage"
                           Opacity="0" />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

乍一看,这似乎运作正常。但我遇到了问题:当我旋转平板电脑时,我在OnApplyTemplate方法之后调用了OnSourcePropertyChanged处理程序。因此,_actualImage字段在OnSourcePropertyChanged处理程序中等于NULL,并且在旋转平板电脑后我没有显示我的图像。

有人知道旋转后Control的工作流程吗?问题出在哪里?

1 个答案:

答案 0 :(得分:0)

通过添加

解决了这个问题 OnApplyTemplate方法中的

VisualStateManager.GoToState(defferedImage, newImageSource == null ? DefaultStateName : ActualStateName, false);