49

WPF に奇妙な問題があります。実行時にディスクから画像を読み込んで、それらを StackView コンテナーに追加していました。ただし、画像は表示されませんでした。いくつかのデバッグの後、トリックを見つけましたが、実際には意味がありません。問題を特定するために小さなデモアプリを作成しました:

新しい WPF プロジェクトを作成し、次のようにコードを貼り付けます。

xaml:

<Window x:Class="wpfBug.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300" Loaded="Window_Loaded">
    <StackPanel Name="sp">
    </StackPanel>
</Window>

xaml.cs、デフォルトの使用法の下に貼り付けます:

namespace wpfBug
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Image i = new Image();
            BitmapImage src = new BitmapImage();
            src.BeginInit();
            src.UriSource = new Uri("picture.jpg", UriKind.Relative);
            src.EndInit();
            i.Source = src;
            i.Stretch = Stretch.Uniform;
            //int q = src.PixelHeight;        // Image loads here
            sp.Children.Add(i);
        }
    }
}

画像を bin/Debug フォルダーにコピーし、「picture.jpg」という名前を付けます。

このプログラムは、コメント行のコメントを解除しない限り、何も表示しません。

私が間違っていること、またはなぜこれが起こるのかを誰かが説明できますか? イメージを削除してプログラムを実行すると、「int q= ...」行で例外が生成されます。その行がコメント化されている場合、イメージが存在しない場合でも、プログラムは例外なく実行されます。必要な場合にのみ画像をロードすることは理にかなっていますが、Image コントロールを StackPanel に追加するときに画像をロードする必要があります。

アイデアはありますか?

編集:ちなみに、画像をリソースとして追加する場合、「int q = ..」行は必要ありません。

4

5 に答える 5

103

創造が遅れたからです。画像をすぐにロードしたい場合は、このコードをinitフェーズに追加するだけです。

src.CacheOption = BitmapCacheOption.OnLoad;

このような:

src.BeginInit();
src.UriSource = new Uri("picture.jpg", UriKind.Relative);
src.CacheOption = BitmapCacheOption.OnLoad;
src.EndInit();
于 2009-02-24T06:56:44.453 に答える
11

画像「Freq.png」がフォルダ「Icons」にあり、「Resource」として定義されている実行中のアセンブリにリソースをロードするコード。

        this.Icon = new BitmapImage(new Uri(@"pack://application:,,,/" 
             + Assembly.GetExecutingAssembly().GetName().Name 
             + ";component/" 
             + "Icons/Freq.png", UriKind.Absolute)); 

誰かがそれを望むなら私も関数を作りました...

/// <summary>
/// Load a resource WPF-BitmapImage (png, bmp, ...) from embedded resource defined as 'Resource' not as 'Embedded resource'.
/// </summary>
/// <param name="pathInApplication">Path without starting slash</param>
/// <param name="assembly">Usually 'Assembly.GetExecutingAssembly()'. If not mentionned, I will use the calling assembly</param>
/// <returns></returns>
public static BitmapImage LoadBitmapFromResource(string pathInApplication, Assembly assembly = null)
{
    if (assembly == null)
    {
        assembly = Assembly.GetCallingAssembly();
    }

    if (pathInApplication[0] == '/')
    {
        pathInApplication = pathInApplication.Substring(1);
    }
    return new BitmapImage(new Uri(@"pack://application:,,,/" + assembly.GetName().Name + ";component/" + pathInApplication, UriKind.Absolute)); 
}

使用法:

        this.Icon = ResourceHelper.LoadBitmapFromResource("Icons/Freq.png");
于 2012-03-16T13:38:37.023 に答える
7

これは奇妙な動作であり、なぜこれが発生しているのかはわかりませんが、いくつかのオプションをお勧めします.

まずは観察です。イメージをコンテンツとして VS に含めて出力ディレクトリにコピーすると、コードが機能します。イメージが VS で None としてマークされている場合、それをコピーしても機能しません。

解決策 1: ファイルストリーム

BitmapImage オブジェクトは、パラメーターとして UriSource または StreamSource を受け入れます。代わりに StreamSource を使用しましょう。

        FileStream stream = new FileStream("picture.png", FileMode.Open, FileAccess.Read);
        Image i = new Image();
        BitmapImage src = new BitmapImage();
        src.BeginInit();
        src.StreamSource = stream;
        src.EndInit();
        i.Source = src;
        i.Stretch = Stretch.Uniform;
        panel.Children.Add(i);

問題: ストリームが開いたままです。このメソッドの最後で閉じると、画像は表示されません。これは、ファイルがシステム上で書き込みロックされたままであることを意味します。

解決策 2: メモリストリーム

これは基本的に解決策 1 ですが、ファイルをメモリ ストリームに読み込み、そのメモリ ストリームを引数として渡します。

        MemoryStream ms = new MemoryStream();
        FileStream stream = new FileStream("picture.png", FileMode.Open, FileAccess.Read);
        ms.SetLength(stream.Length);
        stream.Read(ms.GetBuffer(), 0, (int)stream.Length);

        ms.Flush();
        stream.Close();

        Image i = new Image();
        BitmapImage src = new BitmapImage();
        src.BeginInit();
        src.StreamSource = ms;
        src.EndInit();
        i.Source = src;
        i.Stretch = Stretch.Uniform;
        panel.Children.Add(i);

必要に応じて、システム上のファイルを変更できるようになりました。

于 2009-02-20T14:26:36.387 に答える
2

BitmapImage のさまざまなイベントにハンドラーをアタッチしてみることができます。

画像に関する限り、彼らは何が起こっているかについて少し教えてくれるかもしれません.

于 2009-02-20T14:27:27.477 に答える
0

URI から画像を読み込む拡張メソッドは次のとおりです。

public static BitmapImage GetBitmapImage(
    this Uri imageAbsolutePath,
    BitmapCacheOption bitmapCacheOption = BitmapCacheOption.Default)
{
    BitmapImage image = new BitmapImage();
    image.BeginInit();
    image.CacheOption = bitmapCacheOption;
    image.UriSource = imageAbsolutePath;
    image.EndInit();

    return image;
}

使用例:

Uri _imageUri = new Uri(imageAbsolutePath);
ImageXamlElement.Source = _imageUri.GetBitmapImage(BitmapCacheOption.OnLoad);

そのような単純な!

于 2013-04-16T09:03:40.930 に答える