読者です 読者をやめる 読者になる 読者になる

しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

ストアアプリで大きな画像を表示する場合の注意点

XAML Windows ストアアプリ C# Windows ランタイムアプリ

ストアアプリで大きな画像を表示する場合、

f:id:matatabi_ux:20140215120735j:plain

本来こんな感じに表示される画像が

f:id:matatabi_ux:20140215121459j:plain

こんな風に見切れて表示されてしまうことがあります

原因はわかりませんが、140%、180% の自動スケーリングで利用される画像の横幅や縦幅が 2046px 以上の場合、正しくスケーリングされず見切れてしまうようです

仕方がないので現象回避コード

<UserControl x:Class="WindowsStoreApp9.Controls.SaclingImage"
             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:local="using:WindowsStoreApp9.Controls"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             x:Name="ContentRoot"
             mc:Ignorable="d">

    <Image x:Name="innerImage"
           Width="{Binding Path=Width,
                           ElementName=ContentRoot}"
           Height="{Binding Path=Height,
                            ElementName=ContentRoot}"
           HorizontalAlignment="{Binding Path=HorizontalAlignment,
                                         ElementName=ContentRoot}"
           VerticalAlignment="{Binding Path=VerticalAlignment,
                                       ElementName=ContentRoot}"
           Stretch="{Binding Path=Stretch,
                             ElementName=ContentRoot}" />
</UserControl>

Image コントロールを内包するユーザコントロールを作成して

/// <summary>
/// 手動でスケーリングする画像コントロール
/// </summary>
public sealed partial class SaclingImage : UserControl
{
    #region Source 依存関係プロパティ
    /// <summary>
    /// Source 依存関係プロパティ
    /// </summary>
    public static readonly DependencyProperty SourceProperty
        = DependencyProperty.Register("Source", typeof(string), typeof(SaclingImage), new PropertyMetadata(null, (s, e) =>
    {
        var control = s as SaclingImage;
        if (control != null)
        {
            control.OnSourceChanged();
        }
    }));

    /// <summary>
    /// Source 変更イベントハンドラ
    /// </summary>
    private void OnSourceChanged()
    {
        this.UpdateImage();
    }

    /// <summary>
    /// Source
    /// </summary>
    public string Source
    {
        get { return (string)this.GetValue(SourceProperty); }
        set { this.SetValue(SourceProperty, value); }
    }
    #endregion //Source 依存関係プロパティ

    /// <summary>
    /// コンストラクタ
    /// </summary>
    public SaclingImage()
    {
        this.Stretch = Stretch.Uniform;

        this.InitializeComponent();

        Window.Current.SizeChanged += this.OnSizeChanged;
    }

    /// <summary>
    /// Stretch
    /// </summary>
    public Stretch Stretch { get; set; }

    /// <summary>
    /// サイズ変更イベントハンドラ
    /// </summary>
    /// <param name="sender">イベント発行者</param>
    /// <param name="e">イベント引数</param>
    private void OnSizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
    {
        this.UpdateImage();
    }

    /// <summary>
    /// 子要素破棄時の処理
    /// </summary>
    protected override void OnDisconnectVisualChildren()
    {
        Window.Current.SizeChanged -= this.OnSizeChanged;

        base.OnDisconnectVisualChildren();
    }

    /// <summary>
    ///画像ソースを切り替える
    /// </summary>
    private void UpdateImage()
    {
        var fileName = Path.GetFileName(this.Source);
        var path = this.Source.Replace(fileName, string.Empty);
        var extension = Path.GetExtension(fileName);
        var scaleMode = ResolutionScale.Invalid;

        try
        {
            // デザインモード用
            scaleMode = DisplayInformation.GetForCurrentView().ResolutionScale;
        }
        catch (Exception)
        {
        }

        switch (scaleMode)
        {
            // 100% 表示
            case ResolutionScale.Scale100Percent:
            case ResolutionScale.Scale120Percent:
                this.innerImage.Source = new BitmapImage(
                    new Uri(string.Format("{0}{1}.scale-100{2}", path, fileName.Replace(extension, string.Empty), extension), UriKind.RelativeOrAbsolute));
                break;

            // 140% 表示
            case ResolutionScale.Scale140Percent:
            case ResolutionScale.Scale150Percent:
            case ResolutionScale.Scale160Percent:
                this.innerImage.Source = new BitmapImage(
                    new Uri(string.Format("{0}{1}.scale-140{2}", path, fileName.Replace(extension, string.Empty), extension), UriKind.RelativeOrAbsolute));
                break;

            // 180% 表示
            case ResolutionScale.Scale180Percent:
            case ResolutionScale.Scale225Percent:
            case ResolutionScale.Invalid:
                this.innerImage.Source = new BitmapImage(
                    new Uri(string.Format("{0}{1}.scale-180{2}", path, fileName.Replace(extension, string.Empty), extension), UriKind.RelativeOrAbsolute));
                break;
        }
    }
}

自前でスケーリングによる画像切り替えを行います これで正しくスケーリングがされました

f:id:matatabi_ux:20140215122155p:plain

ちなみにこの場合アプリパッケージ作成時にアプリバンドルを「表示しない」にしないと 140%、180% の画像が分割パッケージされるため、参照できなくて思い通りの動作にならないのでご注意ください