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 = ...」行に例外が生成されます。その行がコメント化されている場合、イメージが存在しなくても、プログラムは例外なく実行されます。ネスセサリーが理にかなっている場合にのみイメージをロードしますが、イメージコントロールをStackPanelに追加するときにイメージをロードする必要があります。
どんなアイデア?
編集:ところで、画像をリソースとして追加する場合、「int q = ..」行は不要です。
創造が遅れたからです。画像をすぐにロードする場合は、このコードをinitフェーズに追加するだけです。
src.CacheOption = BitmapCacheOption.OnLoad;
このような:
src.BeginInit();
src.UriSource = new Uri("picture.jpg", UriKind.Relative);
src.CacheOption = BitmapCacheOption.OnLoad;
src.EndInit();
私の画像「Freq.png」がフォルダ「アイコン」にあり、「リソース」として定義されている実行中のアセンブリにリソースをロードするコード。
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");
これは奇妙な動作であり、これが発生している理由を言うことはできませんが、いくつかのオプションをお勧めできます。
まず、観察。イメージをVSのコンテンツとして含め、出力ディレクトリにコピーすると、コードが機能します。イメージがVSで[なし]としてマークされている場合にコピーすると、機能しません。
解決策1:FileStream
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:MemoryStream
これは基本的にソリューション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);
必要に応じて、システム上のファイルを変更できるようになりました。
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);
そのような単純な!
BitmapImageのさまざまなイベントにハンドラーをアタッチしてみることができます。
画像に関する限り、彼らは何が起こっているかについてあなたに少し話すかもしれません。