【解決方法】MVVM C#​​ を使用して datagrid.columns.count を取得するにはどうすればよいですか?

プログラミングQA


mvvm に続くビューモデル メソッド内で WPF データグリッドの列数を動的に取得するにはどうすればよいですか?

私が試したこと:

本質的に datagrid.columns.count int 変数に変換しますが、mvvm を使用します。

解決策 1

通常はアクセスできないデータ バインディングを介してプロパティにアクセスするには、 Columns.Count のプロパティ DataGrid コントロールの周りにラッパーを記述し、カスタム プロパティを追加できます。

C#
public class MyDataGrid : DataGrid, IDisposable
{
    private const int DefaultColumnCountValue = 0;

    private static readonly Type ctrlType = typeof(MyDataGrid);
    private const string ctrlName = nameof(MyDataGrid);

    public static readonly DependencyProperty ColumnCountProperty =
        DependencyProperty.Register(nameof(ColumnCount),
            typeof(int),
            ctrlType,
            new PropertyMetadata(DefaultColumnCountValue,
                                 OnColumnCountChanged));

    [Bindable(true)]
    [Description("Column Count"), Category(ctrlName)]
    public int ColumnCount
    {
        get => (int)GetValue(ColumnCountProperty);
        set => SetValue(ColumnCountProperty, value);
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        // listen for changes
        this.Columns.CollectionChanged += Columns_CollectionChanged;
    }

    private void Columns_CollectionChanged(
        object? sender,
        NotifyCollectionChangedEventArgs e)
        => ColumnCount = this.Columns.Count;

    private static void OnColumnCountChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        // can do something here when the property value is changed
    }

    public void Dispose()
        => this.Columns.CollectionChanged -= Columns_CollectionChanged;
}

これで、プロパティにバインドできます。

XML
<local:MyDataGrid x:Name="MyDataGrid"
    ColumnCount="{Binding ColumnCount, Mode=OneWayToSource}"
    ItemsSource="{Binding Items}" />

完全なデモは次のとおりです。

1. MainWindow Xaml

XML
<Window x:Class="WpfDataGridCountHelper.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:WpfDataGridCountHelper"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainViewModel />
    </Window.DataContext>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <local:MyDataGrid x:Name="MyDataGrid"
            ColumnCount="{Binding ColumnCount, Mode=OneWayToSource}"
            ItemsSource="{Binding Items}" />

        <Grid Grid.Row="1"
              Margin="10">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Border BorderBrush="DarkGray"
                    BorderThickness="2" 
                    Padding="20 10">
                <TextBlock Margin="0 10" HorizontalAlignment="Stretch">
                    <Run FontWeight="Bold" Text="Column Count: "/>
                    <Run Text="{Binding ColumnCount}"/>
                </TextBlock>
            </Border>
            <Button Grid.Column="1"
                    Margin="10 0 0 0"
                    Padding="20 10"
                    Content="ADD COLUMN"
                    Click="ButtonBase_OnClick"/>
        </Grid>
    </Grid>
</Window>

2. MainWindow ボタン クリック イベントのコード ビハインド (デモ目的のみ):

C#
public partial class MainWindow : Window
{
    public MainWindow() => InitializeComponent();

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        => MyDataGrid.Columns.Add(new DataGridTextColumn());
}

3. MainViewModel + ObservableObject (INotifyPropertyChanged ハンドラークラス)

C#
public abstract class ObservableObject : INotifyPropertyChanged
{
    public void Set<TValue>(
        ref TValue field, 
        TValue newValue, 
        [CallerMemberName] string propertyName = "")
    {
        if (!EqualityComparer<TValue>.Default.Equals(field, default)
            && field!.Equals(newValue))
            return;

        field = newValue;
        PropertyChanged?.Invoke(this,
            new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler? PropertyChanged;
}

public class MainViewModel : ObservableObject
{
    private int columnCount = 0;

    public int ColumnCount
    {
        get => columnCount;
        set => Set(ref columnCount, value);
    }

    public ObservableCollection<PersonModel> Items { get; set; } = new()
    {
        new() { Name = "Freddie", Age = 21 },
        new() { Name = "Milly", Age = 18 },
        new() { Name = "Caddie", Age = 23 },
    };
}


public class PersonModel : ObservableObject
{
    private string? name;
    private int? age;

    public string? Name
    {
        get => name;
        set => Set(ref name, value);
    }

    public int? Age
    {
        get => age;
        set => Set(ref age, value);
    }
}

をクリックすると ADD COLUMN ボタンは、空白の列を追加します MyDataGrid コントロール、次にトリガーをバインドし、 TextBlock フッターの更新で ColumnCount、すべてを介してバインドされます DataContext (MainViewModel)。

楽しみ!

コメント

タイトルとURLをコピーしました