WPFで画像のソース(URI)を動的に指定したいです。
例えば以下のようなImageコントロールがあります。
<Image source="hoge.jpg"/>
この「hoge.jpg」ですが、実行環境により配置されるフォルダ(以下リソースフォルダと称します)が変わります。
リソースフォルダのパスはプログラム内で変数で保持しています。
対象の画像が多いので、コードビハインドで毎回「リソースフォルダ+画像名」のパスを指定するのもスマートじゃないなと思ったので
何か良い方法が無いか探しております(なるべくコードビハインドは変更せず、WPFデザイナには画像が反映される方法が良いです)。
開発環境 .net Framework 4.8
例1
WPF側でコンバータを使う方法
・メリット
コードビハインドは汚れない(コンバータの使いまわしができる)
パフォーマンスはまあ大丈夫そう
・デメリット
全体的に冗長。中でもWPFのImage.Sourceの指定があまりにも冗長。
WPFのデザイナに画像が反映されない。
VB.net
Imports System.Globalization Class MainWindow Private _ResourcePath As String Sub New() InitializeComponent() _ResourcePath = "C:\test\" 'リソースフォルダのパスを指定(最初に一度だけ指定してPG稼働中は変更されない) End Sub Public ReadOnly Property ResourcePath As String Get Return _ResourcePath End Get End Property End Class ’画像ファイル名をパラメータとして渡す Public Class ResourceFolderConverter : Implements IValueConverter Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert Return New Uri(CStr(value) + CStr(parameter)) End Function Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack Throw New NotImplementedException() End Function End Class
WPF
<Window x:Class="MainWindow" 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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp1" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Window.Resources> <local:ResourceFolderConverter x:Key="ResourceFolderConverter"/> </Window.Resources> <Grid> <Image Source="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ResourcePath,Converter={StaticResource ResourceFolderConverter},ConverterParameter=hoge.jpg}"/> </Grid> </Window>
例2
コードビハインドでImageコントロールを検索して書き換え
・メリット
こちらも使いまわしが可能。コードビハインドも汚れない。
WPFのデザイナに画像が表示される。
WPF側はリソースフォルダを意識する必要がない。
・デメリット
Loadedイベント(レンダリング完了後)に画像の差し替えをしているのでパフォーマンスが不安。
※表示まで1秒以上掛かってしまうと問題ありです(実行環境のスペックもそんなに良くない)。そこそこ容量の大きな画像も使う想定です。
相対パスで参照できる画像も用意しなければならない(画像のビルドアクションをResourceでなく、コンテンツなどにして、exe単体で実行できるようにしたい。)
VB.net
Imports System.IO Imports System.Text.RegularExpressions Class MainWindow Private _ResourcePath As String Sub New() InitializeComponent() _ResourcePath = "C:/test/" End Sub Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded For Each img In GetChildrenFromLogical(Of Image)(Me) If TypeOf img.Source Is BitmapFrame Then 'ImageのURIを取得 Dim imageUri = CType(img.Source, BitmapFrame).Decoder.ToString() 'URIのファイル名を取得 Dim fileName = System.IO.Path.GetFileName(imageUri) 'リソースフォルダとファイル名を結合してセットする。 img.Source = New BitmapImage(New Uri(_ResourcePath + fileName)) End If Next End Sub '論理ツリーからコントロール要素を取得 Private Iterator Function GetChildrenFromLogical(Of T As {DependencyObject})(parent As DependencyObject) As IEnumerable(Of T) For Each child In LogicalTreeHelper.GetChildren(parent) If child IsNot Nothing Then If TypeOf child Is T Then Yield CType(child, T) End If If TypeOf child Is DependencyObject Then For Each descendant In GetChildrenFromLogical(Of T)(CType(child, DependencyObject)) Yield descendant Next End If End If Next End Function End Class
WPF
<Window x:Class="MainWindow" 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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp2" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <Image Source="hoge.jpg"/> </Grid> </Window>
そもそも画像のビルドアクションを全てResourceにすれば済む話なのですが、
「エンドユーザーが任意で画像の差し替えを可能にする」必要があり画像はexeに埋め込めないです。
そこそこ需要がありそうなのに、ここまでしなければならないのか....。という感じです....。
簡単な方法があったら教えてほしい次第です。
よろしくお願いいたします。
まだ回答がついていません
会員登録して回答してみよう