none
WPFにて、入れ子にしたControls.ImageとMedia.ImageDrawingをUserControlにするとImageSourceが更新されない問題 RRS feed

  • 質問

  • ForumやStackOverflow等を調べても解決方法が見つかりませんでしたのでこちらで質問させて頂きます。

    ある条件下で、実行中にボタンのクリックイベント等で動的にImageSourceを更新しても画面に画像が反映されない問題です。今のところ判明している条件は以下です。

    • UserControlにまとめて自作メソッド越し、または依存関係プロパティ越しにImageSourceを変更する
    • Image上でSourceに画像を指定するのではなく、Image - DrawingImage - ImageDrawing の入れ子構造にする

    以下のコードで実験してみました。UserControl越しにSourceを指定する場合、依存関係プロパティを使用してもメソッドから直接SourceにBitmapImageを指定しても結果は同じでしたので、より簡潔な依存関係プロパティのみ載せています。

    (1) ImageのSourceを動的に変更する -> Success

    <image Source="" />

    (2) 入れ子にしたImagDrawingを動的に変更する -> Success

    <Image>
    <Image.Source>
        <DrawingImage>
            <DrawingImage.Drawing>
                <ImageDrawing ImageSource="" />
            </DrawingImage.Drawing>
        </DrawingImage>
    </Image.Source>
    </Image>

    (3) UserControlを使用してImageのSourceを変更する -> Success

    <!-- ImgSourceは自作の依存関係プロパティ -->
    <local:UserImageControl ImgSource=""  />
    <!-- 一部省略して要点のみ記述 -->
    <UserControl ....
                 x:Name="UserImageControlName">
        <Grid>
            <Image Source="{Binding ElementName=UserImageControlName, Path=ImgSource}" />
        </Grid>
    </UserControl>

    (4) UserControlを使用して入れ子になったImageDrawingのSourceを変更する ->Failed(ビルド、実行は可能だが画面に画像が表示されない)

    <!-- こちらは全て載せます -->
    <UserControl x:Class="ImageBindingSample001.UserDrawingImageControl"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 x:Name="UserDrawingImageControlName"
                 d:DesignHeight="300" d:DesignWidth="300">
            <Image x:Name="LocalImageControl" Stretch="Uniform">
                <Image.Source>
                    <DrawingImage>
                        <DrawingImage.Drawing>
                            <ImageDrawing x:Name="LocalImageDrawingControl" ImageSource="{Binding ElementName=UserDrawingImageControlName, Path=ImgDrwSource}" />
                        </DrawingImage.Drawing>
                    </DrawingImage>
                </Image.Source>
            </Image>
    </UserControl>


    想像されるのは、UserControlを使用しているときのみ、ImageDrwaingからImageへSource変更通知が行われない、ということです。それがなぜ起こるのか、回避策が思い当たりません。Bitmapオブジェクト生成時に渡される参照がコピーされていないとも考えましたが、メソッドで直接Sourceを変更しても表示されませんでした。(3)と(4)を同時に同じUserControl内に設置して依存関係プロパティを変更すると、Imageコントローラは変更されるのでUserControlの外から中へは画像情報が渡っているような気がします。

    何かヒントでも頂けると幸いです。よろしくお願いいたします。




    • 編集済み leetmikeal 2014年9月19日 2:14 サンプルコードにバグ
    2014年9月19日 1:59

回答

  • Imageと入れ子にして使用したい理由は、ImageのMatrixTransformsを使用したいからです。そのため、ImageDrawingに設定するRectはImageSourceのPixelWidth, PixelHeightを常に使用したいと考えていました。

    この問題に対してはChangedイベントを使用することで解決できました。

    <ImageDrawing Changed="ImageDrawing_Changed" ImageSource="{Binding ElementName=InspImageControl, Path=ImageSourceMaster}" />
            private void ImageDrawing_Changed(object sender, EventArgs e)
            {
                ImageDrawing element = sender as ImageDrawing;
                if(element != null)
                {
                    if(element.ImageSource != null)
                    { 
                        BitmapSource bs = element.ImageSource as BitmapSource;
                        //Console.WriteLine(bs.PixelWidth);
                        //Console.WriteLine(bs.PixelHeight);
                        element.Rect = new Rect(0, 0, bs.PixelWidth, bs.PixelHeight);
                    }
                }
            }

    • 回答としてマーク leetmikeal 2014年9月19日 4:23
    2014年9月19日 4:22

すべての返信

  • 質問者です。

    原因は別のところにありました。ImageDrawingのRectが指定されていないことが原因でした。サンプルプログラムでRectを静的に明示的に指定すると表示されました。もう少し検証してみます。

    ありがとうございました。

    2014年9月19日 2:42
  • Imageと入れ子にして使用したい理由は、ImageのMatrixTransformsを使用したいからです。そのため、ImageDrawingに設定するRectはImageSourceのPixelWidth, PixelHeightを常に使用したいと考えていました。

    この問題に対してはChangedイベントを使用することで解決できました。

    <ImageDrawing Changed="ImageDrawing_Changed" ImageSource="{Binding ElementName=InspImageControl, Path=ImageSourceMaster}" />
            private void ImageDrawing_Changed(object sender, EventArgs e)
            {
                ImageDrawing element = sender as ImageDrawing;
                if(element != null)
                {
                    if(element.ImageSource != null)
                    { 
                        BitmapSource bs = element.ImageSource as BitmapSource;
                        //Console.WriteLine(bs.PixelWidth);
                        //Console.WriteLine(bs.PixelHeight);
                        element.Rect = new Rect(0, 0, bs.PixelWidth, bs.PixelHeight);
                    }
                }
            }

    • 回答としてマーク leetmikeal 2014年9月19日 4:23
    2014年9月19日 4:22