私はwpfdatagridを使用しており、ユーザーが行の1つを調整するときにすべての行の高さを設定する方法を探しています。データグリッドにすべての行の高さを一度に設定するRowHeightプロパティがあることは知っていますが、変更された個々の行の高さをキャッチする方法は私を免れます
4 に答える
そのために直接使用できるイベントはありません。あなたができることは、行やその他のもののサイズを変更したときに発生する別のイベントを使用することです。私が今考えているイベントはPreviewMouseUpです。これは、データグリッドの場合はどこでもマウスボタンを離すとリリースされます。
イベントが発生したときにできることは、すべての行の行の高さを確認し、異なる行を見つけて、それですべての行を更新することです。
試行錯誤でこれにたどり着きました。ItemsSourceデータソースを使用している限り、問題なく動作するはずです。これは仮想行で機能するはずであり、視覚的な一時停止が短時間発生するだけで、切り替えられます(これは主に列の自動生成に起因するため、回避できます)。
ハックが進むにつれて、それは単純であり、変更されることが期待されていないメカニズムを使用するという利点があります。
ユーザーによるアクションのトリガーに関するヒューリスティックは改善される可能性がありますが、まだ失敗していません。
using Microsoft.Windows.Controls;
using Microsoft.Windows.Controls.Primitives;
public static class DataGridExtensions
{
public static void LinkRowHeightsToUserChange(this DataGrid dataGrid)
{
double? heightToApply = null;
bool userTriggered = false;
if (dataGrid.RowHeaderStyle == null)
dataGrid.RowHeaderStyle = new Style(typeof(DataGridRowHeader));
if (dataGrid.RowStyle == null)
dataGrid.RowStyle = new Style(typeof(DataGridRow));
dataGrid.RowStyle.Setters.Add(new EventSetter()
{
Event = DataGridRow.SizeChangedEvent,
Handler = new SizeChangedEventHandler((r, sizeArgs) =>
{
if (userTriggered && sizeArgs.HeightChanged)
heightToApply = sizeArgs.NewSize.Height;
})
});
dataGrid.RowHeaderStyle.Setters.Add(new EventSetter()
{
Event = DataGridRowHeader.PreviewMouseDownEvent,
Handler = new MouseButtonEventHandler(
(rh,e) => userTriggered = true)
});
dataGrid.RowHeaderStyle.Setters.Add(new EventSetter()
{
Event = DataGridRowHeader.MouseLeaveEvent,
Handler = new MouseEventHandler((o, mouseArgs) =>
{
if (heightToApply.HasValue)
{
userTriggered = false;
var itemsSource = dataGrid.ItemsSource;
dataGrid.ItemsSource = null;
dataGrid.RowHeight = heightToApply.Value;
dataGrid.ItemsSource = itemsSource;
heightToApply = null;
}
})
});
}
@アラン
この背後にある理論的根拠を覚えていますか?
私はあなたに言うことができます:アイテムソースの設定を解除してリセットするために両方の行を削除すると(実際にプロセス全体がかなり遅くなります)、サイズを変更する行の高さが確実に設定されます。
行のサイズを変更すると、その高さを直接変更するように見えます。これにより、特にこの行のdataGridのRowHeightプロパティに設定した値が上書きされます。だから基本的に、これがあなたが得ることができるものです:
dataGridのRowHeight=20
1つの行の高さ(たとえば5番目)を30に変更します=>この行の高さは30に設定され、dataGridのRowHeightは30に設定されます。これまでのところすべてが良好に見えます。
ここで、別の行の高さを20に戻します(2行目など)。この行の高さを20に設定し、DataGridのRowHeightを20に設定します。これにより、5番目の行が30のままである場合を除いて、他のすべての行が20になります(以前はこの値に強制されていたため)。
ソースを空にしてリセットすると、各行が強制的に再ロードされ、dataGridのRowHeightが考慮されます。これにより、問題が解消されます。
私の知る限り、行の高さのサイズを変更したときに発生するイベントはありません。
私の最初の提案は、DataGridRowのheightプロパティとdatagridのRowHeightプロパティの間にバインディング(OneWay)を作成するためにRowStyleを設定することですが、サイズを変更した後で行の高さを確認すると、変更されません。ActualHeightはサイズを変更したときの行の「実際の」高さを含むプロパティ。「アクセス可能なセットアクセサーがない」ため、ActualHeightを設定できません。
これを試した後、私は考えました:DataGridRowのActualHeightはどこからその値を取得しますか?
クリックされたセルと行を検出する方法を説明し、DataGridのデフォルトのテンプレートビジュアルツリーも表示するこの投稿を思い出しました。
試行錯誤の結果(上のリンクのビジュアルツリー画像を使用)、使用されていた高さを保存したのはDataGridCellPresenterであることがわかりました(実際、これについては100%確信が持てません。これは、高さのある最初のクラスでした。 DataGridCell以降のビジュアルツリーを変更しました)。
どうやらDataGridはDataGridRowからDataGridCellsPresenterを取得するためのAPIを公開していません(私がここで見つけたように)
したがって、私の最初のアプローチは、データが入力された後に(ビジュアルツリーを介して)DataGrid内のすべてのDataGridCellPresenterを取得し、DataGridPresenterのHeightプロパティとDataGridのRowHeightプロパティの間にバインディングをプログラムで作成することでした。
これを行うためのコードは次のとおりです(私のDataGridのインスタンス名はdataGrid1です):
すべてのDataGridCellPresenterを取得します。
void GetAllDataGridCellPresenters(DependencyObject parent, List<DataGridCellsPresenter> presenters)
{
int numberOfChildren = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numberOfChildren; i++)
{
if (VisualTreeHelper.GetChild(parent, i) is DataGridCellsPresenter)
{
presenters.Add(VisualTreeHelper.GetChild(parent, i) as DataGridCellsPresenter);
}
else if (VisualTreeHelper.GetChild(parent, i) != null)
{
GetAllDataGridCellPresenters(VisualTreeHelper.GetChild(parent, i), presenters);
}
else
return;
}
}
それらすべてにプログラムでバインディングを設定します(LoadedイベントがDataGridによって発生したときにこれを呼び出します):
void SetBindingInDataGridPresenter()
{
List<DataGridCellsPresenter> presenters = new List<DataGridCellsPresenter>();
GetAllDataGridCellPresenters(dataGrid1, presenters);
foreach (DataGridCellsPresenter presenter in presenters)
{
Binding binding = new Binding("RowHeight");
binding.Source = dataGrid1;
binding.Mode = BindingMode.TwoWay;
presenter.SetBinding(DataGridCellsPresenter.HeightProperty, binding);
}
}
(注:バインディングをOneWayToSourceとして設定しても機能しませんでした。理由はよくわかりません。おそらく、ここで明らかな何かが欠落しています...)
これは機能しました...一種の...ビジュアルツリーを使用してDataGridCellsPresenterを取得したため、表示されているもののみを取得しました:Pですが、これはこの方法で実行できることを示しています。
したがって、最後に、それを行う正しい方法は、DataGridコントロールテンプレートを提供することです。これは、DataGridのRowHeightプロパティにバインドされたDataGridCellsPresenterのHeightプロパティデータを除いて、デフォルトのテンプレートと同じです。
これが正確な方法を示していないことは知っていますが、コントロールのテンプレートを再定義する方法を学ぶ必要があります(I:Pもそうです) 。どういうわけかデフォルトのDataGridテンプレートを取得します(または、すでに別の素晴らしいテンプレートを使用している場合は、おそらく私よりもそれについて知っていて、DataGridCellsPresenterHeightプロパティをRowHeightDataGridプロパティに自動的にバインドするための方法をすでに知っています)両方の高さプロパティをバインドする魔法のビットでそれを変更します。