質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

XAML

XAML(Extensible Application Markup Language)はWPF、Silverlight、Windows PhoneそしてWindows Store appsでユーザーインターフェースを定義するために使われるXML言語です。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

1回答

2117閲覧

WPF DataGridCellのサイズが取得したいが挙動が想定と違う

hibin0bin0

総合スコア2

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

XAML

XAML(Extensible Application Markup Language)はWPF、Silverlight、Windows PhoneそしてWindows Store appsでユーザーインターフェースを定義するために使われるXML言語です。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

0グッド

0クリップ

投稿2021/06/07 17:19

前提・実現したいこと

DataGridのセルに波形を描画するために試行錯誤している内容です。
描画にあたってセルの実寸が必要になるので
今回の目的は「各行の該当セルのサイズ(あるいは内部のサイズ)を常に把握する」ことです。

発生している問題・エラーメッセージ

最初に起動した時点で目に見えているセルのサイズ取得はできているものの
下にスクロールして隠れていた行を表示させると、適切に取得できていないことがわかりました。

2種類のやり方で試してみましたがいずれも安定しませんでした。
1.TemplateColumnにGrid継承コントロールをタテヨコStretchで配置し、そのRenderSizeをSizeChangedイベント発生時に取得する
2.DataGridCellにEventSetterでSizeChangedイベントを置き、そこから取得

DataGridにバインドしたリストで各行の該当セルのサイズを表示させています。
いずれにしても次の画像の通り、先頭数行は数値が代入されているのに下のほうは0のままです。
RenderSizeを取得しているため、見た目通りのサイズが代入されるはずという想定でした。
イメージ説明イメージ説明

しっかり青い領域(NewGrid)が見えているのに高さ幅の値が0のままなのはなぜでしょうか。
コードの問題点、解決策があればお願いいたします。

該当のソースコード

C#

1using System; 2using System.Collections.Generic; 3using System.Windows; 4using System.ComponentModel; 5using System.Diagnostics; 6using System.Windows.Controls; 7 8 9namespace TestApp 10{ 11 /// <summary> 12 /// Interaction logic for MainWindow.xaml 13 /// </summary> 14 public partial class MainWindow : Window, INotifyPropertyChanged 15 { 16 public MainWindow() 17 { 18 InitializeComponent(); 19 20 this.DataContext = this; 21 22 } 23 24 //変更通知 25 public event PropertyChangedEventHandler PropertyChanged; 26 private void OnPropertyChanged(string propertyName) 27 { 28 this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 29 } 30 31 32 33 public List<Item> list 34 { 35 get 36 { 37 return _list; 38 } 39 set 40 { 41 _list = value; 42 OnPropertyChanged("list"); 43 } 44 } 45 List<Item> _list; 46 47 48 private void Window_ContentRendered(object sender, EventArgs e) 49 { 50 List<Item> l = new List<Item>(); 51 for (int i = 0; i < 10; i++) 52 { 53 l.Add(new Item()); 54 } 55 56 list = l; 57 58 } 59 60 //2番目のやり方用 61 private void Cell_SizedChanged(object sender, SizeChangedEventArgs e) 62 { 63 DataGridCell c = (DataGridCell)sender; 64 DataGridRow r = DataGridRow.GetRowContainingElement(c); 65 66 ((List<Item>)dataGrid.ItemsSource)[r.GetIndex()].gridSize = c.RenderSize; 67 } 68 69 } 70} 71

XAML

1<Window x:Class="TestApp.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:TestApp" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="450" Width="800" ContentRendered="Window_ContentRendered"> 9 10 <DataGrid x:Name="dataGrid" ScrollViewer.CanContentScroll="True" ItemsSource="{Binding list}" RowHeight="100" AutoGenerateColumns="False"> 11 <DataGrid.Columns> 12 <DataGridTemplateColumn x:Name="WaveColumn" Header="波形" Width="200" IsReadOnly="True"> 13 <DataGridTemplateColumn.CellTemplate> 14 <DataTemplate> 15 <!--1番目のやり方用--> 16 <local:NewGrid HorizontalAlignment="Stretch" 17 VerticalAlignment="Stretch" 18 Background="Aqua" 19 GridSize="{Binding gridSize, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"/> 20 </DataTemplate> 21 </DataGridTemplateColumn.CellTemplate> 22 23 <!--2番目のやり方用--> 24 <DataGridTemplateColumn.CellStyle> 25 <Style TargetType="DataGridCell"> 26 <EventSetter Event="SizeChanged" Handler="Cell_SizedChanged" /> 27 </Style> 28 </DataGridTemplateColumn.CellStyle> 29 </DataGridTemplateColumn> 30 <DataGridTextColumn Binding="{Binding height}" Width="100" Header="height"/> 31 <DataGridTextColumn Binding="{Binding width}" Width="100" Header="width"/> 32 </DataGrid.Columns> 33 </DataGrid> 34</Window> 35

DataGridにバインドしたリストの項目

C#

1using System.Windows; 2using System.ComponentModel; 3 4namespace TestApp 5{ 6 public class Item : INotifyPropertyChanged 7 { 8 public int height 9 { 10 get 11 { 12 return _height; 13 } 14 set 15 { 16 _height = value; 17 OnPropertyChanged("height"); 18 } 19 } 20 21 int _height; 22 23 public int width 24 { 25 get 26 { 27 return _width; 28 } 29 set 30 { 31 _width = value; 32 OnPropertyChanged("width"); 33 } 34 } 35 36 int _width; 37 38 public Size gridSize 39 { 40 get 41 { 42 return new Size(width, height); 43 } 44 set 45 { 46 if (value.Height != 0.0) 47 { 48 width = (int)value.Width; 49 height = (int)value.Height; 50 } 51 } 52 } 53 54 public event PropertyChangedEventHandler PropertyChanged; 55 private void OnPropertyChanged(string propertyName) 56 { 57 this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 58 } 59 } 60} 61

Gridを継承したNewGrid
DependencyPropertyを登録してRenderSizeを間接的にバインドできるようにしたもの

C#

1 2using System.Windows; 3using System.Windows.Controls; 4using System.Diagnostics; 5 6namespace TestApp 7{ 8 public class NewGrid : Grid 9 { 10 public NewGrid() 11 : base() 12 { 13 SizeChanged += new SizeChangedEventHandler(NewGrid_SizeChanged); 14 } 15 16 void NewGrid_SizeChanged(object sender, SizeChangedEventArgs e) 17 { 18 GridSize = RenderSize; 19 } 20 21 public Size GridSize 22 { 23 get { return (Size)GetValue(GridSizeProperty); } 24 set { SetValue(GridSizeProperty, value); 25 } 26 } 27 28 public static readonly DependencyProperty GridSizeProperty = 29 DependencyProperty.Register("GridSize", typeof(Size), typeof(NewGrid), 30 new PropertyMetadata(new Size())); 31 } 32 33} 34

補足情報(FW/ツールのバージョンなど)

VS 2019
C# XAML

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TN8001

2021/06/07 21:17

VirtualizingStackPanel.VirtualizationMode="Standard" にすれば大体想定通りになるとは思います。 ですが、目的は「波形を描画する」であって、サイズをバインドすることじゃないんですよね? 波形を描画するコントロールを作ることになるでしょうが、そのコントロールは当然自身のサイズは知っているわけですから、べつにVMにサイズを供給する必要もないように思うのですが。
hibin0bin0

2021/06/08 03:05

>べつにVMにサイズを供給する必要もないように思うのですが。 NewGridの場合直接サイズは取得できますが、そのNewGridがdataGridの何行目のものなのかを知る方法がわからなかったためバインドすることで「何行目のNewGridのサイズ」を管理できると考えました。 Cellを見る場合は確かにバインドの必要がないかもしれません。 Virtualizing~~について後ほど確認してみます。 ありがとうございます。
hibin0bin0

2021/06/08 04:21

Virtualizing~~を確認し、想定通りに動作したことを確認しました。 ありがとうございます。
TN8001

2021/06/08 05:09

解決されたようで何よりです。 > そのNewGridがdataGridの何行目のものなのかを知る方法 何らかのソースがあるのでしょうから、例えば何かのファイルパスや波形の生データのようなものを、依存関係プロパティでバインドすることになるんじゃないでしょうか。 ソートやフィルターしてしまうと行番号もあまり意味はないですし。
hibin0bin0

2021/06/08 06:38

波形データの表示領域の再計算(Item内に実装)をするためにバインドしようという発想でしたが そもそも再計算をNewGridクラス内でやってしまえばVMに渡す必要がない、という認識で合っていますか? 読んでいてなるほど、と思いました。 参考にしてもう少し賢いコードが書ける気がします。 波形描画に関する情報を省略していたにもかかわらずアドバイスいただきありがとうございます。
TN8001

2021/06/08 06:52

> そもそも再計算をNewGridクラス内でやってしまえばVMに渡す必要がない、という認識で合っていますか? そうです。 どう表示するかは完全にViewの都合ですのでVMが絡む必要はありません。 表示するソースといくつかの表示のオプションがあれば十分でしょう。
guest

回答1

0

自己解決

コメントにいただいた通り、
VirtualizingStackPanel.VirtualizationMode="Standard"を設定することで
サイズを正常に取得できました。

XAML

1<DataGrid x:Name="dataGrid" ScrollViewer.CanContentScroll="True" ItemsSource="{Binding list}" RowHeight="100" AutoGenerateColumns="False" 2VirtualizingStackPanel.VirtualizationMode="Standard"> <!--これを追加--> 3</DataGrid>

投稿2021/06/08 04:24

hibin0bin0

総合スコア2

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問