かずきのBlog

C#やJavaやRubyとメモ書き

目次

Blog 利用状況

ニュース

わんくまBlogが不安定になったため、前に書いてたはてなダイアリーにメインを移動します。
かずきのBlog@Hatena
技術的なネタは、こちらにも、はてなへのリンクという形で掲載しますが、雑多ネタははてなダイアリーだけに掲載することが多いと思います。
コメント
プログラマ的自己紹介
お気に入りのツール/IDE
プロフィール
経歴
広告
アクセサリ

書庫

日記カテゴリ

[WPF][C#]WPFで画像ビューワ作ってみた

ちょっと時間があったので、WPFで画像ビューワ作ってみました。
実行結果は下の通り。
image

開くボタンで、フォルダを指定すると、その中の画像のサムネイルを表示する。
表示されたサムネイルの中から、適当な画像を選択すると、その画像が画面の中央部分に表示される。
拡大縮小・回転もすることが出来る。

画像は一応jpg, bmp, png, tiff, gifあたりが見えるはず。

この見た目を作るためにバックで保持している情報は

public class ImageInfo
{
    public string Path { get; set; }
}

というstring型のプロパティを1つもつだけのクラスのリストだけ。
後はXAMLでサムネイル表示や、選択されたものを中心に表示したり、拡大縮小・回転をやってる。
XAMLが、どれだけ表現力があるかというのがわかると思う。

というわけで、これから、これとなるべく同じものをもう一度作りながらBlog記事を書いていってみようと思う。

プロジェクトの作成

とりあえずWPFアプリケーションの形式のプロジェクトを作成します。
名前は、WpfImageViewerApplicationにしました。

プロジェクトを作成したら、以下の手順でメインウィンドウをViewerWindowに変更します。

  1. Window1.xamlを削除
  2. プロジェクトの右クリックで表示されるメニューから追加→ウィンドウで、ViewerWindow.xamlを新規作成
  3. App.xamlのStartupUriをViewerWindow.xamlにする

ここまでの手順でソリューションエクスプローラは下のような感じになります。
image

App.xamlは、下のようになります。

<Application x:Class="WpfImageViewerApplication.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="ViewerWindow.xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>

指定したフォルダから画像だけ取得する処理

WPFとは直接関係無い部分をさくっと作っていきます。
今回は、bmp, jpg, png, tiff, gifあたりのファイルを、特定のフォルダから抜き出したいので、その処理を書いていきます。

Commonというフォルダを作って、そこにImageUtilsというクラスを作成します。
image

WPFとはかすってもいない処理なので、さくっとコードを書きます。

using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace WpfImageViewerApplication.Common
{
    /// <summary>
    /// 画像ビューワの便利メソッド集
    /// </summary>
    public static class ImageUtils
    {
        /// <summary>
        /// 指定したフォルダから、指定した拡張子のファイルを
        /// ImageInfo型のリストにして返す。
        /// </summary>
        /// <param name="directory">ファイルを探すディレクトリへのパス</param>
        /// <param name="supportExts">探す拡張子</param>
        /// <returns>引数で指定した条件に合致する画像の情報</returns>
        public static IList<ImageInfo> GetImages(string directory, string[] supportExts)
        {
            if (!Directory.Exists(directory))
            {
                // ディレクトリが無い時は空のリストを返す
                return new List<ImageInfo>();
            }
            var dirInfo = new DirectoryInfo(directory);
            // ディレクトリからファイルを拡張子で絞り込んで返す
            return dirInfo.GetFiles().
                Where(f => supportExts.Contains(f.Extension)).
                Select(f => new ImageInfo { Path = f.FullName }).
                ToList();
        }
    }

    /// <summary>
    /// 画像に関する情報を持たせるクラス
    /// </summary>
    public class ImageInfo
    {
        /// <summary>
        /// 画像ファイルへのパス
        /// </summary>
        public string Path { get; set; }
    }
}

裏の肝となる処理がこれでできました。
次は、画面に表示するためのモデルクラスを作成していきます。

モデルクラスの作成

ViewerWindowのDataContextに設定するモデルクラスを作成します。
ViewerWindowModelという名前のクラスを作成して、INotifyPropertyChangedを実装させます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace WpfImageViewerApplication
{
    /// <summary>
    /// ViewerWindowのモデルクラス
    /// </summary>
    public class ViewerWindowModel : INotifyPropertyChanged
    {
        #region コンストラクタ
        public ViewerWindowModel()
        {
            // OnPropertyChangedでnullチェックするのがめんどいので
            // 空の処理をあらかじめ1つ追加しておく。
            PropertyChanged += (sender, e) => { };
        }
        #endregion

        #region INotifyPropertyChanged メンバ

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string name)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
        #endregion
    }
}

そして、画面に表示するデータを保持するためのプロパティを定義します。
プロパティの型はさっき定義したImageInfoのIListになります。

#region プロパティ
private IList<ImageInfo> _images;
/// <summary>
/// ビューワーで表示する画像の情報を取得または設定します。
/// </summary>
public IList<ImageInfo> Images
{
    get
    {
        return _images;
    }
    set
    {
        _images = value;
        OnPropertyChanged("Images");
    }
}
#endregion

次に、指定したフォルダの画像を読み込むという処理を書きます。
処理自体は、先ほど作成したImageUtilsクラスのメソッドを呼ぶだけなのですが、フォルダをユーザに選択してもらう処理を書く必要があります。そのためにSystem.Windows.Forms.FolderBrowserDialogを使います。

System.Windows.Forms.FolderBrowserDialogは、System.Windows.Formsを参照に追加します。
image

若干前後しますが、Windows Formのダイアログの見た目をモダンっぽくするためにAppクラスのStartupイベントにEnableVisualStylesを呼び出す処理を書きます。
さらに、アプリケーションでサポートする拡張子を取得するプロパティと、現在のアプリケーションのインスタンスをApp型で返すプロパティも追加しておきます。

App.xaml
<Application x:Class="WpfImageViewerApplication.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Startup="Application_Startup"
    StartupUri="ViewerWindow.xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>

App.xaml.cs

using System.Windows;

namespace WpfImageViewerApplication
{
    /// <summary>
    /// App.xaml の相互作用ロジック
    /// </summary>
    public partial class App : Application
    {
        private string[] _supportExts = { ".jpg", ".bmp", ".png", ".tiff", ".gif" };
        /// <summary>
        /// アプリケーションでサポートするファイルの拡張子を取得する。
        /// </summary>
        public string[] SupportExts
        {
            get { return _supportExts; }
        }

        /// <summary>
        /// 現在のAppクラスのインスタンスを取得する
        /// </summary>
        public static new App Current
        {
            get { return Application.Current as App; }
        }

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            // モダンな見た目にするために、ここで呼び出しておく。
            System.Windows.Forms.Application.EnableVisualStyles();
        }
    }
}

下準備が終わったので、ViewerWindowModelクラスにOpenDirectoryメソッドを追加して、以下の内容を書きます。
FolderBrowserDialogでディレクトリを選択したら、その中から画像ファイルを取得してImagesプロパティを更新するような内容になっています。

#region 公開メソッド
public void OpenDirectory()
{
    using (var dialog = new System.Windows.Forms.FolderBrowserDialog())
    {
        if (dialog.ShowDialog() != System.Windows.Forms.DialogResult.OK)
        {
            // OK以外は何もしない
            return;
        }
        // Imagesプロパティを、選択された画像のリストに更新する
        this.Images = ImageUtils.GetImages(
            dialog.SelectedPath, App.Current.SupportExts);
    }
}
#endregion

これで、裏方の処理が実装完了。
続いてXAMLを書いていきます。

画面を作成

まずは、名前空間の定義を行います。
ImageInfoクラスと、ViewerWindowModelクラスは確実にXAML内で使うので、Windowタグの部分に以下の二行の定義を足します。

xmlns:local="clr-namespace:WpfImageViewerApplication"
xmlns:common="clr-namespace:WpfImageViewerApplication.Common"

ついでに、WidthとHeightの定義を消して、Windowの大きさが、環境に合わせた大きさになるようにしておきます。
そして、タイトルをWPF画像ビューワーに変更します。DataContextにViewerWindowModelクラスも設定しておきます。

ここまでで、XAMLは以下のようになります。

<Window x:Class="WpfImageViewerApplication.ViewerWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfImageViewerApplication"
    xmlns:common="clr-namespace:WpfImageViewerApplication.Common"
    Title="WPF画像ビューワー">
    <Window.DataContext>
        <local:ViewerWindowModel />
    </Window.DataContext>
    <Grid>
        
    </Grid>
</Window>

全体のラフなレイアウトの決定

XAMLで、全体のラフなコントロールの配置を考えていきます。
今回は、画面上部にボタンや、スライダーなどのアプリケーションを操作する系のコントロールを配置して、その下に、サムネイルを表示する領域を設けて、残りを画像を表示する部分として利用します。
こんなレイアウトをするのにぴったりなのはDockPanelということで、Windowの直下をDockPanelにします。

Top部分にStackPanelとListBoxを順番に配置して、CenterにImageを含んだScrollViewerを配置します。
Top部分のStackPanelには、ボタンやスライダーの入ったGroupBoxを配置しておきます。

<Window x:Class="WpfImageViewerApplication.ViewerWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfImageViewerApplication"
    xmlns:common="clr-namespace:WpfImageViewerApplication.Common"
    Title="WPF画像ビューワー">
    <Window.DataContext>
        <local:ViewerWindowModel />
    </Window.DataContext>
    <DockPanel>
        <StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
            <GroupBox Header="操作">
                <Button Name="buttonOpen" Content="開く" />
            </GroupBox>
            <GroupBox Header="拡大/縮小">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="X.X倍:" />
                    <Slider Name="sliderZoom" Minimum="0.1" Maximum="5.0" Width="75"/>
                </StackPanel>
            </GroupBox>
            <GroupBox Header="回転">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="XXX度:" />
                    <Slider Name="sliderRotate" Minimum="0" Maximum="360" Width="75" SmallChange="1" LargeChange="90" />
                </StackPanel>
            </GroupBox>
        </StackPanel>
        <ListBox DockPanel.Dock="Top">
        </ListBox>
        <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
            <Image />
        </ScrollViewer>
    </DockPanel>
</Window>

ここまで実行すると、下のようになります。
 image

開くボタンの実装

続いて開くボタンを実装します。
コマンドを使おうかと思いましたが、今回はお手軽なイベントで実装しました。
ButtonタグにClickイベントを登録して、以下の処理を書きます。

using System.Windows;

namespace WpfImageViewerApplication
{
    public partial class ViewerWindow : Window
    {
        public ViewerWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// このウィンドウに関連付けられたモデルを取得します。
        /// </summary>
        public ViewerWindowModel Model
        {
            get { return DataContext as ViewerWindowModel; }
        }

        private void buttonOpen_Click(object sender, RoutedEventArgs e)
        {
            // Modelに委譲する
            this.Model.OpenDirectory();
        }
    }
}

これでボタンを押すと、実際にフォルダにある画像が読み込まれますが、このままだと何も実行結果がわからないので、ListBoxにバインドしてみます。

<ListBox DockPanel.Dock="Top"
         ItemsSource="{Binding Images}">
</ListBox>

これで実行して結果を確認します。
起動して開くボタンを押下
image

ダイアログが出てくるのでサンプルピクチャを選択
image

サンプルピクチャ内の画像?がきっとListBoxに出てると思われる
image

 

ここまでで、基本的にC#のコードを書くのは終わりです。(多分)
ここからは、ガリガリとXAMLを書いて実行結果を確認して仕上げていくという感じになります。

でも、今日は眠いのでここまでzzz

続く!

投稿日時 : 2009年1月12日 0:40

Feedback

# [WPF][C#]WPFで画像ビューワ作ってみた その2 2009/01/12 12:59 かずきのBlog

[WPF][C#]WPFで画像ビューワ作ってみた その2

# re: [WPF][C#]WPFでカスタムコントロールを作ってみよう その2 2009/03/31 23:24 かずきのBlog

re: [WPF][C#]WPFでカスタムコントロールを作ってみよう その2

# thanks for the postmishertAtroro 2010/11/09 2:10 Prostate Gland Problems

Do you people have a facebook fan page? I looked for one on twitter but could not discover one, I would really like to become a fan!

# upgrade key for windows 7 ultimate 2012/08/02 21:42 Boarieevecedak

windows key work 32 bit 64 bit windows 7 rc key
windows 7 key

# get a new windows 7 product key 2012/08/03 2:54 Boarieevecedak

windows ultimate product key july 2010 product key for windows 7 ultimate 32 bit free
windows 7 product key free download

# windows 7 key icon 2012/08/04 5:34 Boarieevecedak

buy windows 7 ultimate product key online windows 7 key invalid
add windows key to kms

# get your windows key 2012/08/04 10:16 Boarieevecedak

windows quote key not working free windows 7 product key download
windows 7 kms key

# windows 7 64 bit cd key 2012/08/05 13:35 Boarieevecedak

windows key working watch v vulxemojo2e how much is a windows 7 product key
microsoft windows 7 key

# windows 7 activation key ultimate 2012/08/05 18:28 Boarieevecedak

windows key jelly bean windows 7 ultimate product key 2010
windows 7 key words

# ガガミラノ 時計コピー 2017/10/10 3:19 jjtfiu@ocn.ne.jp

★★超人気質屋★

★最高等級時計大量入荷!▽★▽世界の一流ブランド品N級の専門ショップ ★
注文特恵中-新作入荷!-価格比較.送料無料!
★主要取扱商品 バッグ、財布、腕時計、ベルト!
★全国送料一律無料
★オークション、楽天オークション、売店、卸売りと小売りの第一選択のブランドの店。
★信用第一、良い品質、低価格は 私達の勝ち残りの切り札です。
★ 当社の商品は絶対の自信が御座います。
おすすめ人気ブランド腕時計, 最高等級時計大量入荷!
★N品質シリアル付きも有り 付属品完備!
☆★☆━━━━━━━━━━━━━━━━━━━☆★☆
以上 宜しくお願い致します。(^0^)
広大な客を歓迎して買います

# A品バーバリー 2017/10/31 9:37 dcpmih@live.jp

コーチのバッグ購入しました。
思った以上の質で、アウトレットで買うよりも、お得だと思いました。
梱包もとても丁寧で、遠方でも まさかの送料無料!!
本当に感激です。
また 利用させていただきます。
ありがとうございました。

# As the admin of this web site is working, no doubt very soon it will be famous, due to its feature contents. 2019/05/02 18:02 As the admin of this web site is working, no doubt

As the admin of this web site is working, no doubt very soon it will be famous, due to its feature contents.

# Great information. Lucky me I discovered your website by chance (stumbleupon). I have saved it for later! 2019/05/03 18:27 Great information. Lucky me I discovered your webs

Great information. Lucky me I discovered your website by
chance (stumbleupon). I have saved it for later!

# You could certainly see your enthusiasm in the article you write. The sector hopes for even more passionate writers such as you who are not afraid to mention how they believe. Always follow your heart. natalielise pof 2019/07/26 20:59 You could certainly see your enthusiasm in the art

You could certainly see your enthusiasm in the article you write.

The sector hopes for even more passionate writers
such as you who are not afraid to mention how they believe.

Always follow your heart. natalielise pof

# You could certainly see your enthusiasm in the article you write. The sector hopes for even more passionate writers such as you who are not afraid to mention how they believe. Always follow your heart. natalielise pof 2019/07/26 21:00 You could certainly see your enthusiasm in the art

You could certainly see your enthusiasm in the article you write.

The sector hopes for even more passionate writers
such as you who are not afraid to mention how they believe.

Always follow your heart. natalielise pof

# You could certainly see your enthusiasm in the article you write. The sector hopes for even more passionate writers such as you who are not afraid to mention how they believe. Always follow your heart. natalielise pof 2019/07/26 21:01 You could certainly see your enthusiasm in the art

You could certainly see your enthusiasm in the article you write.

The sector hopes for even more passionate writers
such as you who are not afraid to mention how they believe.

Always follow your heart. natalielise pof

# You could certainly see your enthusiasm in the article you write. The sector hopes for even more passionate writers such as you who are not afraid to mention how they believe. Always follow your heart. natalielise pof 2019/07/26 21:02 You could certainly see your enthusiasm in the art

You could certainly see your enthusiasm in the article you write.

The sector hopes for even more passionate writers
such as you who are not afraid to mention how they believe.

Always follow your heart. natalielise pof

# I'm extremely inspired with your writing skills as well as with the layout in your weblog. Is this a paid theme or did you modify it your self? Anyway stay up the excellent high quality writing, it is uncommon to peer a great blog like this one nowadays 2019/08/19 17:18 I'm extremely inspired with your writing skills as

I'm extremely inspired with your writing skills as well as
with the layout in your weblog. Is this a
paid theme or did you modify it your self? Anyway stay up the
excellent high quality writing, it is uncommon to peer a great blog like this one nowadays..

# I'm extremely inspired with your writing skills as well as with the layout in your weblog. Is this a paid theme or did you modify it your self? Anyway stay up the excellent high quality writing, it is uncommon to peer a great blog like this one nowadays 2019/08/19 17:19 I'm extremely inspired with your writing skills as

I'm extremely inspired with your writing skills as well as
with the layout in your weblog. Is this a
paid theme or did you modify it your self? Anyway stay up the
excellent high quality writing, it is uncommon to peer a great blog like this one nowadays..

# I'm extremely inspired with your writing skills as well as with the layout in your weblog. Is this a paid theme or did you modify it your self? Anyway stay up the excellent high quality writing, it is uncommon to peer a great blog like this one nowadays 2019/08/19 17:20 I'm extremely inspired with your writing skills as

I'm extremely inspired with your writing skills as well as
with the layout in your weblog. Is this a
paid theme or did you modify it your self? Anyway stay up the
excellent high quality writing, it is uncommon to peer a great blog like this one nowadays..

# I'm extremely inspired with your writing skills as well as with the layout in your weblog. Is this a paid theme or did you modify it your self? Anyway stay up the excellent high quality writing, it is uncommon to peer a great blog like this one nowadays 2019/08/19 17:21 I'm extremely inspired with your writing skills as

I'm extremely inspired with your writing skills as well as
with the layout in your weblog. Is this a
paid theme or did you modify it your self? Anyway stay up the
excellent high quality writing, it is uncommon to peer a great blog like this one nowadays..

# ブランド通販店 2019/09/23 5:46 MarquisTax

弊社は各ランクのブランド商品満載し、ブランド通販店で一番信用のある店なので!。
品質はこちらが間違いなく保証します。
https://www.ginzaoff.com/watch/product-5661.html


■取扱ブランド ロレックス時計コピー、カルティエ時計コピー、IWC時計コピー、
ブライトリング時計コピー、パネライ時計コピー.
◆ スタイルが多い、品質がよい、価格が低い、実物写真!
◆ ご入金頂いてから最速4日、遅くとも7日程度でご指定場所へ発送出来る予定でございます
◆ 商品送料を無料にいたします
https://www.ginzaoff.com/bag/product-17384.html

◆信用第一、良い品質、低価格は 私達の勝ち残りの切り札です。
◆ 当社の商品は絶対の自信が御座います。
◇ N品質 シリアル付きも有り 付属品完備!
https://www.ginzaoff.com/watch/menu-page-5-35.html

◆ 必ずご満足頂ける品質の商品のみ販売しております。
◇ 品質を最大限本物と同等とする為に相応の材質にて製作している為です。
◆ 絶対に満足して頂ける品のみ皆様にお届け致します。
興味あれば、是非一度サイトをご覧になって下さい。
今後ともよろしくご愛顧くださいますよう、お願い申し上げます
https://www.ginzaoff.com/watch/product-24394.html

お取り引きを開始させていただきたく思います。
詳細に関してはどうぞお気軽にご連絡ください。

# This is my first time go to see at here and i am actually happy to read everthing at alone place. 2019/11/25 5:42 This is my first time go to see at here and i am a

This is my first time go to see at here and i am actually happy to read everthing at alone place.

# I am really impressed with your writing skills as well as with the layout on your weblog. Is this a paid theme or did you customize it yourself? Anyway keep up the excellent quality writing, it's rare to see a great blog like this one today. 2019/12/07 1:56 I am really impressed with your writing skills as

I am really impressed with your writing skills as well as with the
layout on your weblog. Is this a paid theme or did you customize it yourself?
Anyway keep up the excellent quality writing, it's rare to see a great blog like this one
today.

# My coder is trying to persuade me to move to .net from PHP. I have always disliked the idea because of the costs. But he's tryiong none the less. I've been using WordPress on numerous websites for about a year and am anxious about switching to another 2019/12/17 12:35 My coder is trying to persuade me to move to .net

My coder is trying to persuade me to move to .net from PHP.

I have always disliked the idea because of the costs.
But he's tryiong none the less. I've been using WordPress on numerous websites for about a year and am anxious about switching
to another platform. I have heard great things about blogengine.net.
Is there a way I can transfer all my wordpress posts into it?
Any kind of help would be greatly appreciated!

# 6 Compare prices and The more money 1 2020/01/01 3:19 Typicalcat04

https://www.zapatita.com/%ef%bb%bfmost-active-senior-online-dating-sites-no-fee/ colorado albanian senior dating online site https://www.pellegrini-rubichara.com/mature-online-dating-services-absolutely-free-blogs.wankuma.com.pdf america korean senior dating online website https://angelbedarf-kaufen.de/2019/08/08/%ef%bb%bfmost-legitimate-senior-online-dating-site-without-payments/ the uk iranian mature dating online website http://printingdeals.co.uk/senior-dating-online-site-no-membership-blogs.wankuma.com.pdf where to meet muslim seniors in london free

# Heya just wanted to give you a quick heads up and let you know a few of the pictures aren't loading correctly. I'm not sure why but I think its a linking issue. I've tried it in two different browsers and both show the same results. 2020/01/07 6:42 Heya just wanted to give you a quick heads up and

Heya just wanted to give you a quick heads up and let
you know a few of the pictures aren't loading correctly.
I'm not sure why but I think its a linking issue. I've tried it
in two different browsers and both show the same results.

# Hi there, yeah this article is really good and I have learned lot of things from it on the topic of blogging. thanks. 2020/06/20 18:35 Hi there, yeah this article is really good and I h

Hi there, yeah this article is really good and I have learned lot of things from it on the topic of blogging.
thanks.

# When I initially commented I clicked the "Notify me when new comments are added" checkbox and now each time a comment is added I get four e-mails with the same comment. Is there any way you can remove me from that service? Thanks a lot! 2020/06/29 13:55 When I initially commented I clicked the "Not

When I initially commented I clicked the "Notify me when new comments are added" checkbox and
now each time a comment is added I get four e-mails with the same comment.

Is there any way you can remove me from that service? Thanks
a lot!

# Hello colleagues, its wonderful article on the topic of cultureand fully explained, keep it up all the time. 2020/08/10 10:40 Hello colleagues, its wonderful article on the top

Hello colleagues, its wonderful article on the
topic of cultureand fully explained, keep it up all
the time.

# It's hard to find experienced people on this subject, but you seem like you know what you're talking about! Thanks 2020/08/14 14:15 It's hard to find experienced people on this subje

It's hard to find experienced people on this subject,
but you seem like you know what you're talking about! Thanks

タイトル  
名前  
Url
コメント