質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

1回答

7154閲覧

WPFで画像を動的に指定したい

Mashimasa

総合スコア50

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

1グッド

0クリップ

投稿2022/03/08 05:48

編集2022/03/08 08:13

WPFで画像のソース(URI)を動的に指定したいです。

例えば以下のようなImageコントロールがあります。
<Image source="hoge.jpg"/>
この「hoge.jpg」ですが、実行環境により配置されるフォルダ(以下リソースフォルダと称します)が変わります。

リソースフォルダのパスはプログラム内で変数で保持しています。

対象の画像が多いので、コードビハインドで毎回「リソースフォルダ+画像名」のパスを指定するのもスマートじゃないなと思ったので
何か良い方法が無いか探しております(なるべくコードビハインドは変更せず、WPFデザイナには画像が反映される方法が良いです)。

開発環境 .net Framework 4.8

例1
WPF側でコンバータを使う方法

・メリット
コードビハインドは汚れない(コンバータの使いまわしができる)
パフォーマンスはまあ大丈夫そう

・デメリット
全体的に冗長。中でもWPFのImage.Sourceの指定があまりにも冗長。
WPFのデザイナに画像が反映されない。

VB.net

1Imports System.Globalization 2 3Class MainWindow 4 Private _ResourcePath As String 5 6 Sub New() 7 InitializeComponent() 8 _ResourcePath = "C:\test\" 'リソースフォルダのパスを指定(最初に一度だけ指定してPG稼働中は変更されない) 9 End Sub 10 11 Public ReadOnly Property ResourcePath As String 12 Get 13 Return _ResourcePath 14 End Get 15 End Property 16End Class 17 18’画像ファイル名をパラメータとして渡す 19Public Class ResourceFolderConverter : Implements IValueConverter 20 Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert 21 Return New Uri(CStr(value) + CStr(parameter)) 22 End Function 23 Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack 24 Throw New NotImplementedException() 25 End Function 26End Class

WPF

1<Window x:Class="MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:WpfApp1" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="450" Width="800"> 9 <Window.Resources> 10 <local:ResourceFolderConverter x:Key="ResourceFolderConverter"/> 11 </Window.Resources> 12 <Grid> 13 <Image Source="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ResourcePath,Converter={StaticResource ResourceFolderConverter},ConverterParameter=hoge.jpg}"/> 14 </Grid> 15</Window>

例2
コードビハインドでImageコントロールを検索して書き換え

・メリット
こちらも使いまわしが可能。コードビハインドも汚れない。
WPFのデザイナに画像が表示される。
WPF側はリソースフォルダを意識する必要がない。

・デメリット
Loadedイベント(レンダリング完了後)に画像の差し替えをしているのでパフォーマンスが不安。
※表示まで1秒以上掛かってしまうと問題ありです(実行環境のスペックもそんなに良くない)。そこそこ容量の大きな画像も使う想定です。
相対パスで参照できる画像も用意しなければならない(画像のビルドアクションをResourceでなく、コンテンツなどにして、exe単体で実行できるようにしたい。)

VB.net

1Imports System.IO 2Imports System.Text.RegularExpressions 3 4Class MainWindow 5 Private _ResourcePath As String 6 7 Sub New() 8 InitializeComponent() 9 _ResourcePath = "C:/test/" 10 End Sub 11 12 Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded 13 For Each img In GetChildrenFromLogical(Of Image)(Me) 14 If TypeOf img.Source Is BitmapFrame Then 15           'ImageのURIを取得 16 Dim imageUri = CType(img.Source, BitmapFrame).Decoder.ToString() 17           'URIのファイル名を取得 18 Dim fileName = System.IO.Path.GetFileName(imageUri) 19           'リソースフォルダとファイル名を結合してセットする。 20 img.Source = New BitmapImage(New Uri(_ResourcePath + fileName)) 21 End If 22 Next 23 End Sub 24 25 '論理ツリーからコントロール要素を取得 26 Private Iterator Function GetChildrenFromLogical(Of T As {DependencyObject})(parent As DependencyObject) As IEnumerable(Of T) 27 For Each child In LogicalTreeHelper.GetChildren(parent) 28 If child IsNot Nothing Then 29 If TypeOf child Is T Then 30 Yield CType(child, T) 31 End If 32 If TypeOf child Is DependencyObject Then 33 For Each descendant In GetChildrenFromLogical(Of T)(CType(child, DependencyObject)) 34 Yield descendant 35 Next 36 End If 37 End If 38 Next 39 End Function 40 41End Class

WPF

1<Window x:Class="MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:WpfApp2" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="450" Width="800"> 9 <Grid> 10 <Image Source="hoge.jpg"/> 11 </Grid> 12</Window>

そもそも画像のビルドアクションを全てResourceにすれば済む話なのですが、
「エンドユーザーが任意で画像の差し替えを可能にする」必要があり画像はexeに埋め込めないです。

そこそこ需要がありそうなのに、ここまでしなければならないのか....。という感じです....。
簡単な方法があったら教えてほしい次第です。

よろしくお願いいたします。

TN8001👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2022/03/08 07:13

読んでください→ https://teratail.com/help/question-tips 自分ではどこまで実装できていて、どこで躓いていて、何が分かれば解決できるかを、自分が書いたコードをアップするなどして説明できませんか? 今の質問ではなる投げで、ここではマイナス評価対象です。 あと、開発環境を書きましょう。
Mashimasa

2022/03/08 08:08

失礼しました。 開発環境とサンプルコードを追加しました。
guest

回答1

0

ベストアンサー

マークアップ拡張はどうですかね。
マークアップ拡張と XAML - WPF .NET Framework | Microsoft Docs

VBできないのでC#で^^;
えらい雑ですがお好みに改造してください^^;

xml

1<Window 2 x:Class="Qvilrvy7pfiwusg.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:local="clr-namespace:Qvilrvy7pfiwusg" 6 Width="800" 7 Height="450"> 8 <StackPanel> 9 <HeaderedContentControl Header="Source=&quot;KnkDDC5A_thumbnail.jpg&quot;"> 10 <Image Source="KnkDDC5A_thumbnail.jpg" Stretch="None" /> 11 </HeaderedContentControl> 12 <HeaderedContentControl Header="Source=&quot;{local:Hoge KnkDDC5A_thumbnail.jpg}&quot;"> 13 <Image Source="{local:Hoge KnkDDC5A_thumbnail.jpg}" Stretch="None" /> 14 </HeaderedContentControl> 15 </StackPanel> 16</Window>

cs

1using System; 2using System.Windows; 3using System.Windows.Markup; 4using System.Windows.Media.Imaging; 5 6namespace Qvilrvy7pfiwusg 7{ 8 public class HogeExtension : MarkupExtension 9 { 10 public static string? Path; 11 12 private readonly string source; 13 14 public HogeExtension(string source) => this.source = source; 15 16 public override object ProvideValue(IServiceProvider serviceProvider) 17 { 18 return Path == null 19 ? new BitmapImage(new Uri(source, UriKind.Relative)) 20 : new BitmapImage(new Uri(System.IO.Path.Combine(Path, source))); 21 22 // 配下でいいならこっちのほうが楽?(HogeExtension.Path = "Resources/"; のような 23 //return new BitmapImage(new Uri($"pack://siteoforigin:,,,/{Path}{source}")); 24 } 25 } 26 27 28 public partial class MainWindow : Window 29 { 30 public MainWindow() 31 { 32 HogeExtension.Path = @"C:\hoge\fuga\Teratail\Qvilrvy7pfiwusg\bin\Debug\net6.0-windows\Resources\"; 33 34 InitializeComponent(); 35 } 36 } 37}

開発中はどちらもソリューション内のjpgを見るため表示される。
Resourcesフォルダや中のファイルは、ソリューション管理外で手動で追加している(ユーザーが指定したテイ)
開発中

実行時はマークアップ拡張を使った下のほうだけが(予定通り)出る。
アプリ画像

投稿2022/03/08 10:11

編集2023/07/30 05:06
TN8001

総合スコア9317

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Mashimasa

2022/03/08 23:33

ありがとうございます! これですねやりたかったのは! 一つ利口になりました。
Mashimasa

2022/03/09 02:25

開発環境(VisualStudio2019)での画像のパス指定がうまくいかず、はまったので追記しておきます。 プロジェクトフォルダ ┠Resource ┃  ┗hoge.jpg ┗UI  ┗Window.xaml 上記のようなフォルダ構成の時は「UI」フォルダがカレントディレクトリになるようでした。  →× New BitmapImage(New Uri("res/hoge.jpg"))   「リソースを検索できません」とエラーになってしまう。 Resourceフォルダを指定したい場合はXamlが配置されているフォルダを起点に相対パスを指定する必要がありました。  →〇 New BitmapImage(new Uri("../res/hoge.jpg"))     
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問