HeyCHのブログ

慢性疲労のへいちゃんです

【C#】WPFのBitmapの取り扱いについて

例えば、ある画像ファイルがあって、それを特定の場所にコピーして、画像を表示。
表示したら削除するという処理があるとします。

これWindowsフォームアプリケーションだったら簡単に実装できるんですけど、
WPFの場合はちょっとややこしいことをしないとだめだという事がわかったのでメモしておきます。

<Window x:Class="WritableBitmap.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:WritableBitmap"
        mc:Ignorable="d"
        Title="MainWindow" Height="225" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="25"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Button Grid.Row="0" x:Name="ShowButton" Content="押せ!" Click="show_image"/>
        <ListView Grid.Row="1" x:Name="listView">
            <ListView.View>
            <GridView>
                    <GridViewColumn Header="DateTime" DisplayMemberBinding="{Binding DateTime}"/>
                    <GridViewColumn Header="Status" DisplayMemberBinding="{Binding Status}"/>
            </GridView>
            </ListView.View>
        </ListView>
        <Image Grid.Row="2" x:Name="MainImage"/>
    </Grid>
</Window>
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WritableBitmap {
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
        }

        private async void show_image(object sender, RoutedEventArgs e) {
            ShowButton.IsEnabled = false;
            var str_date = DateTime.Now.ToString("yyyy/MM/dd/ HH:mm:ss");
            try {
                await Task.Run(() => {
                    while (true) {
                        //----------async loop start------------/

                        String origin_image_path = @"C:\Users\BlackTomato\Documents\Sample.png";
                        String dst_image_path = @"C:\Users\BlackTomato\Documents\Sample2.png";
                        File.Copy(origin_image_path, dst_image_path, true);

                        //lock less bitmap
                        var end_date = DateTime.Now.ToString("yyyy/MM/dd/ HH:mm:ss");
                        this.Dispatcher.Invoke((Action)(() => {
                            listView.Items.Add(new Data { DateTime = str_date, Status = "Start" });
                            listView.Items.Add(new Data { DateTime = end_date, Status = "End" });
                            //ここから
                            BitmapImage bmp = new BitmapImage();
                            bmp.BeginInit();
                            bmp.CacheOption = BitmapCacheOption.OnLoad;
                            bmp.UriSource = new Uri(dst_image_path);
                            bmp.EndInit();
                            WriteableBitmap wbmp = new WriteableBitmap(bmp);
                            //ここまで
                            this.MainImage.Source = wbmp;
                        }));

                        File.Delete(dst_image_path);
                        System.Threading.Thread.Sleep(1000);
                        //-------------async loop end---------------/
                    }
                });
            } catch {

            } finally {
                ShowButton.IsEnabled = true;

            }
        }
    }
    public class Data {
        public string DateTime { get; set; }
        public string Status { get; set; }
    }
}

上記の「//ここから」「//ここまで」の部分なのですが、

  • Dispatcherの外にBitmapImageを持っていくとエラーになる。
  • Dispatcherの外でエラーにならないように書いても画像が表示されなかったり、画像削除、またはコピー時にエラーになったりする。

事がわかりました。
特に下の原因はわかりにくいためWPFアプリを作る上で問題になることが多いような気がします。