77975


現在、社内で依頼されて、C#のWPFで一覧にチェック入れて保存する画面を作成しています。  
WPFは初めてなのですが、調べながらすすめています。  
イベントハンドリングやDBへの登録の仕組みは作ることができました。

しかし、動的レイアウトで画面に記載した赤枠内の１段２段構成の表が動的に作成できません。（静的でもうまくいきません）

GRIDを作成して、行を追加するプログラム（RowDefinitions.Add）を組めば、赤枠の中が１セットで次々連続になることはわかっています。

このレイアウト部分について、どのように書けばいいのか教えていただけないでしょうか。

[![画像の説明をここに入力](https://i.stack.imgur.com/2zjYo.png)](https://i.stack.imgur.com/2zjYo.png)


CC BY-SA 4.0
2021-07-04T15:40:03.713
77972
2021-07-05T22:13:27.180
47156
question
c# wpf
WPFでの表の動的レイアウト生成の方法について


質問するときは環境に関する情報を詳しく記述しましょう。

  * [技術系メーリングリストで質問するときのパターン・ランゲージ](https://www.hyuki.com/writing/techask.html#env)

まずはVisual Studioのバージョンや、ターゲットフレームワークのバージョン (.NET Frameworkまたは.NET Coreのバージョン)
を提示してください。バージョンによって利用できる機能が変わるため、回答も変わる可能性があります。

ひとまずVisual Studio 2015以降、.NET Framework 4.5以降の環境であると仮定します。

テーブル内のすべてのレコードについて、カラムの数と種別が同じなのであれば、  
わざわざ[Grid](https://docs.microsoft.com/en-
us/dotnet/api/system.windows.controls.grid)を使うまでもなく、[ListView](https://docs.microsoft.com/en-
us/dotnet/api/system.windows.controls.listview)を使って[GridViewColumn](https://docs.microsoft.com/en-
us/dotnet/api/system.windows.controls.gridviewcolumn)の`Header`と`CellTemplate`を指定すればよいと思います。

また、WPFではデータバインディングを使い、MVVMパターンで実装するのがセオリーです。  
[INotifyPropertyChanged](https://docs.microsoft.com/en-
us/dotnet/api/system.componentmodel.inotifypropertychanged)インターフェイスを実装することで双方向バインディングもできます。  
双方向バインディングでは、バインディングターゲット (View) への操作がバインディングソース (ViewModel)
に直接反映され、またバインディングソースへの操作がバインディングターゲットに直接反映されるので、コードビハインドで個々の[Control](https://docs.microsoft.com/en-
us/dotnet/api/system.windows.controls.control)や[UIElement](https://docs.microsoft.com/en-
us/dotnet/api/system.windows.uielement)を操作するコードを書く必要がありません。

MVVM実装を簡素化する[Prism](https://prismlibrary.com/index.html)などの外部フレームワークもありますが、とりあえず標準ライブラリのみを使用したオーソドックスなコードを書いておきます。

MainWindow.xaml:

[code]

    <Window x:Class="WpfApplication1.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:WpfApplication1"
            mc:Ignorable="d"
            Title="MainWindow" Width="550" Height="350"
            WindowStartupLocation="CenterScreen"
            >
        <Grid Margin="10">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="10"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Label Grid.Row="0" Content="チェック表:"/>
            <ListView Grid.Row="1" x:Name="listView1" ItemsSource="{Binding}" VirtualizingPanel.IsVirtualizing="True" ScrollViewer.VerticalScrollBarVisibility="Visible">
                <ListView.ItemContainerStyle>
                    <Style TargetType="ListViewItem">
                        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                    </Style>
                </ListView.ItemContainerStyle>
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="要約" DisplayMemberBinding="{Binding Path=Summary}">
                        </GridViewColumn>
                        <GridViewColumn Header="チェック時刻">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBox Width="100" Text="{Binding Path=CheckedDateTime, StringFormat={}{0:yyyy-MM-dd HH:mm}}"/>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="チェック内容1">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <CheckBox HorizontalAlignment="Center" IsChecked="{Binding IsItem1Checked}"/>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="チェック内容2">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <CheckBox HorizontalAlignment="Center" IsChecked="{Binding IsItem2Checked}"/>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="チェック内容3">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <CheckBox HorizontalAlignment="Center" IsChecked="{Binding IsItem3Checked}"/>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="チェック内容4">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <CheckBox HorizontalAlignment="Center" IsChecked="{Binding IsItem4Checked}"/>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                    </GridView>
                </ListView.View>
                <ListView.ItemsPanel>
                    <ItemsPanelTemplate>
                        <VirtualizingStackPanel Orientation="Vertical" CanVerticallyScroll="True"/>
                    </ItemsPanelTemplate>
                </ListView.ItemsPanel>
            </ListView>
            <Button Grid.Row="3" x:Name="buttonRegister" Content="登録" HorizontalAlignment="Right" Padding="15,0" Click="buttonRegister_Click"/>
        </Grid>
    </Window>
    
[/code]

MainWindow.xaml.cs:

[code]

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Runtime.CompilerServices;
    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 WpfApplication1
    {
        /// <summary>
        /// MainWindow.xaml の相互作用ロジック
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                // バインディングソースの作成。
                for (int i = 0; i < 10; ++i)
                {
                    var obj = new MyViewModel() { Summary = $"{i} についての確認" };
                    _viewModel.Add(obj);
                }
    
                // バインディングソースの設定。
                // ItemsSource に対応する。
                this.listView1.DataContext = _viewModel;
            }
    
            private readonly ObservableCollection<MyViewModel> _viewModel = new ObservableCollection<MyViewModel>();
    
            private static string ToYorN(bool x)
            {
                return x ? "Y" : "N";
            }
    
            private void buttonRegister_Click(object sender, RoutedEventArgs e)
            {
                // テスト。
                var sb = new StringBuilder();
                foreach (var obj in _viewModel)
                {
                    string line = $"{obj.Summary}: Time={obj.CheckedDateTime:yyyy-MM-dd HH:mm}, #1={ToYorN(obj.IsItem1Checked)}, #2={ToYorN(obj.IsItem2Checked)}, #3={ToYorN(obj.IsItem3Checked)}, #4={ToYorN(obj.IsItem4Checked)}";
                    System.Diagnostics.Debug.WriteLine(line);
                    sb.Append(line);
                    sb.Append("\n");
                }
                MessageBox.Show(sb.ToString());
            }
        }
    
        public class MyViewModel : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
            protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
            {
                this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
    
            private string _summary = "";
            private DateTime _checkedDateTime = new DateTime();
            private bool _isItem1Checked = false;
            private bool _isItem2Checked = false;
            private bool _isItem3Checked = false;
            private bool _isItem4Checked = false;
    
            public string Summary
            {
                get { return _summary; }
                set
                {
                    _summary = value;
                    this.NotifyPropertyChanged();
                }
            }
    
            public DateTime CheckedDateTime
            {
                get { return _checkedDateTime; }
                set
                {
                    _checkedDateTime = value;
                    this.NotifyPropertyChanged();
                }
            }
    
            public bool IsItem1Checked
            {
                get { return _isItem1Checked; }
                set
                {
                    _isItem1Checked = value;
                    this.NotifyPropertyChanged();
                }
            }
    
            public bool IsItem2Checked
            {
                get { return _isItem2Checked; }
                set
                {
                    _isItem2Checked = value;
                    this.NotifyPropertyChanged();
                }
            }
    
            public bool IsItem3Checked
            {
                get { return _isItem3Checked; }
                set
                {
                    _isItem3Checked = value;
                    this.NotifyPropertyChanged();
                }
            }
    
            public bool IsItem4Checked
            {
                get { return _isItem4Checked; }
                set
                {
                    _isItem4Checked = value;
                    this.NotifyPropertyChanged();
                }
            }
        }
    }
    
[/code]

もしレコードごとにチェックボックスの説明テキストを変えたいのであれば、例えばViewModelクラスに`string`型のプロパティ
(`Item1Description`, `Item2Description`, ...)
を別途用意して、[CheckBox](https://docs.microsoft.com/en-
us/dotnet/api/system.windows.controls.checkbox)の`Content`プロパティにバインディングするなどの方法があります。  
あとは自分で応用してください。


CC BY-SA 4.0
2021-07-04T19:41:46.487
77975
2021-07-05T22:13:27.180
2021-07-05T22:13:27.180
15413
15413
77972
answer