XAMLを使わないWPF入門11「プログラムによるテンプレート生成でサムネイル」

コンピュータ

ListViewを使って画像の一覧を表示します。

過去にXAMLで作った記事がありましたので、XAMLを使わないバージョンを作成して見まいた。
XAML版
C#のWPFのListViewを使って画像の一覧を表示するサンプル。
画像が保存されたディレクトリで、大き目の画像でサムネイル表示が出来ないか調べてみました。プロジェクトの作成mkdir プロジェクト名cd プロジェクト名dotnet new wpfdotnet add package Microsoft.X...

同じ用に作って見ましたが、サムネイル画像とファイル名が重なる用になったので、StackPanelを使うように変更しています。

プロジェクトの作成

cd (mkdir NoXAML11)
dotnet new wpf -f net8.0
dotnet add package ReactiveProperty.WPF
rm *.xaml
rm MainWindow.xaml.cs

ソースコード

ファイル名:NoXAML11.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net8.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <UseWPF>true</UseWPF>
    <StartupObject>NoXAML11.App</StartupObject>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="ReactiveProperty.WPF" Version="9.7.0" />
  </ItemGroup>

</Project>

ファイル名:MainWindowViewModel.cs

using System.ComponentModel;
using Reactive.Bindings;
using System.IO;

namespace ImageListView
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
       public event PropertyChangedEventHandler? PropertyChanged;
        protected virtual void OnPropertyChanged(string name) =>
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        
        public ReactiveCollection<ImageInfoEntity> Images { get; private set; } = [];

        public MainWindowViewModel()
        {
            string dirPath = "C:\\Users\\karet\\Pictures\\20250628";

            foreach(var file in Directory.EnumerateFiles(dirPath))
            {
                if (Path.GetExtension(file).ToLower() == ".png")
                    Images.AddOnScheduler(new ImageInfoEntity(file));
            }
        }
    }
}

ファイル名:ImageInfoEntity.cs

public class ImageInfoEntity
{
    public string Title { get => System.IO.Path.GetFileName(Path); }
    public string Path {get; private set;}
    public ImageInfoEntity(string path)
    {
        Path = path;
    }
}

ファイル名:App.xaml.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using ImageListView;

namespace NoXAML11;

public partial class App : Application
{
    private static void App_Startup(object sender, StartupEventArgs e)
    {
        // ビューモデル
        var viewModel = new MainWindowViewModel();

        // Gridのルート
        var rootGrid = new Grid();

        // ListView作成
        var listView = new ListView
        {
            SelectionMode = SelectionMode.Extended
        };

        // ItemsSourceバインディング
        var binding = new Binding(nameof(MainWindowViewModel.Images))
        {
            Source = viewModel,
        };
        listView.SetBinding(ItemsControl.ItemsSourceProperty, binding);

        // ScrollViewerの水平スクロールバーを無効化
        ScrollViewer.SetHorizontalScrollBarVisibility(listView, ScrollBarVisibility.Disabled);

        // ItemsPanel: WrapPanelに変更
        var itemsPanelFactory = new FrameworkElementFactory(typeof(WrapPanel));
        listView.ItemsPanel = new ItemsPanelTemplate(itemsPanelFactory);

        // ItemTemplate作成
        var itemTemplate = new DataTemplate();

        // StackPanel を使う(縦並び)
        var stackFactory = new FrameworkElementFactory(typeof(StackPanel));
        stackFactory.SetValue(StackPanel.OrientationProperty, Orientation.Vertical);
        stackFactory.SetValue(FrameworkElement.WidthProperty, 288.0);
        stackFactory.SetValue(FrameworkElement.HeightProperty, 288.0);

        // Image(上)
        var imageFactory = new FrameworkElementFactory(typeof(Image));
        imageFactory.SetBinding(Image.SourceProperty, new Binding("Path"));
        imageFactory.SetValue(FrameworkElement.HeightProperty, 256.0);
        imageFactory.SetValue(Image.StretchProperty, Stretch.Uniform);
        stackFactory.AppendChild(imageFactory);

        // TextBlock(下)
        var textFactory = new FrameworkElementFactory(typeof(TextBlock));
        textFactory.SetBinding(TextBlock.TextProperty, new Binding("Title"));
        textFactory.SetValue(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Center);
        textFactory.SetValue(TextBlock.TextWrappingProperty, TextWrapping.Wrap);
        textFactory.SetValue(TextBlock.TextTrimmingProperty, TextTrimming.CharacterEllipsis);
        stackFactory.AppendChild(textFactory);

        itemTemplate.VisualTree = stackFactory;
        listView.ItemTemplate = itemTemplate;

        rootGrid.Children.Add(listView);

        // ウィンドウ
        var window = new Window
        {
            Title = "サムネイル",
            Width = 800,
            Height = 450,
            Content = rootGrid,
            DataContext = viewModel,
        };
        window.Show();

    }

    [STAThread]
    public static void Main()
    {
        var app = new App();
        app.Startup += App_Startup;
        app.Run();
    }
}

実行

dotnet run

コメント