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

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

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

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

Visual Studio 2010

Microsoft Visual Studio 2010はMicrosoftが提供している統合開発環境(IDE)です。

.NET Framework 4.0

Microsoft Windows用のソフトウェア開発環境/実行環境である .NET Frameworkの4番目のメジャーバージョンです。

WPF

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

Q&A

解決済

2回答

10411閲覧

【WPF】DataGridの一括選択の実装

退会済みユーザー

退会済みユーザー

総合スコア0

C#

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

Visual Studio 2010

Microsoft Visual Studio 2010はMicrosoftが提供している統合開発環境(IDE)です。

.NET Framework 4.0

Microsoft Windows用のソフトウェア開発環境/実行環境である .NET Frameworkの4番目のメジャーバージョンです。

WPF

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

0グッド

0クリップ

投稿2016/12/12 05:27

現在DataGridのアイテムの一括選択を右クリックで実装しようとしています。
DataGridのMouseRightButtonUpイベントで処理を行っており、
始めに選択されていたRowの場所とShiftを押されながら右クリックされた場所の
インデックスを使用しforで回して間のアイテムのIsSelectedをTrueにしていくという処理なのですが、

DataGridのインスタンスからRowを取得するときの
ItemContainerGenerator.ContainerFromIndex()でnullを返してくる場合がありうまくいきません。

nullを返してくる条件なのですが、Item数が多くScrollBarが出ている状態で画面外になっているアイテムが
nullを返してきています。

いろいろ調べて、UpdateLayout()やScrollIntoView()を所得前に行うようにしてみたのですが解決できませんでした。

なにか解決策があればぜひ教えていただきたいです。
よろしくお願いいたします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

#原因
ほとんどのWPFのリストコントロール(DataGridやListView等)は既定で仮想化されており、描画範囲外のコントロールが存在しません。
このため、コントロールベースでこの手の操作を実装をしようとすると失敗します。

#対策
対策は2つあります。1つはアイテムコンテナの仮想化を止めること、もう1つはデータバインディングによって選択済みのアイテムを取得することです。基本的には後者の方がパフォーマンス上ベターです。

#サンプル
データバインディングを使用した選択行を取得する方法を紹介します。どこまでMVVMに準拠するのかによってコーディングは変わってきますが、今回ご紹介するのは最も簡単と思われる方法です。必要であればこちらをBehavior等にすると良いでしょう。

CommandParameterにDataGridのSelectedItemsをバインドすると、選択されたItemのコレクションを取得できます。

XML

1<DataGrid x:Name="MyDataGrid" ItemsSource="{Binding Items}"> 2 <i:Interaction.Triggers> 3 <!-- 下記のようにすればMouseRightButtonUpイベントとバインドできます --> 4 <i:EventTrigger EventName="MouseRightButtonUp"> 5 <i:InvokeCommandAction 6 Command="{Binding ShowSelectedCommand}" 7 CommandParameter="{Binding ElementName=MyDataGrid, Path=SelectedItems}" /> 8 </i:EventTrigger> 9 </i:Interaction.Triggers> 10</DataGrid>

Presenter/ViewModelクラス上の実装

C#

1public ICommand ShowSelectedCommand 2{ 3 get 4 { 5 // DelegateCommandは一般的なICommand実装を想定していますが、分からなければ再度聞いてください 6 return _ShowSelectedCommand = _ShowSelectedCommand ?? 7 new DelegateCommand(showSelected); 8 } 9} 10private ICommand _ShowSelectedCommand; 11 12private void showSelected(object parameter) 13{ 14 // SelectedItemsの型はSelectedItemCollectionという型ですが非公開です 15 // IList型に一旦キャストした後、Castメソッドで目的のコレクションに変換します。 16 var items = (parameter as IList)?.Cast<MyItem>(); 17 if (items != null) 18 { 19 // このようにすれば、MyItemsから選択されたMyItemの一覧を取得できます。 20 // ここで目的のItemのIsSelectedプロパティをtrueに設定すれば良いでしょう。 21 MessageBox.Show(string.Join(",", items.Select(item => item.Index))); 22 } 23}

サンプルはSystem.Windows.Interactivityを使用しています。
プロジェクトの参照にSystem.Windows.Interactivityを追加し、XAMLのWindow/UserControlには以下の名前空間を定義してください。

XML

1<Window ... 2 xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 3/>

投稿2016/12/13 03:20

編集2016/12/14 01:03
haru666

総合スコア1591

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

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

haru666

2016/12/13 03:28

.NET Framework 4.0での動作確認はしていますが、VS2015で確認したため、上手く動かないときはすみません。
退会済みユーザー

退会済みユーザー

2016/12/15 01:34

教えていただいた方法でいろいろ試してみているのですが、DataGridにBindされているItemsはUI上でソートされても並びが変わらないようなのですが、それだとソート時の一括選択でViewModel上では処理できないとおもうのですが、何か方法はあるのでしょうか? 元々この処理自体が初めから自分で考えたわけではなくプロジェクト上の同じような場所から持ってきたものになります。 ソートやフィルターなどでの並べ替え等を考慮してのコードビハインド上の処理かなと思うのですがViewModel側で実装できるでしょうか?
haru666

2016/12/15 01:54

DataGridにBindされているItemsのことは一旦忘れてください。 上記で提案した方法の場合、BindされたItemsの選択されたItemだけのコレクションがshowSelectedでは取得できているため、選択対象への操作が必要な場合に大本のItemsに触れる必要はありません。   お話から察するに、コレクションビューは使用されていると思います。 ICollectionView view = CollectionViewSource.GetDefaultView(MyItems);   このソートは大本のMyItemsには影響を与えません。しかし、ShowSelectedCommandに渡されたパラメーター側のアイテムの一覧は選択されたMyItemが、「選択順」で入ってきます。 (例えば、1,2,3,8,5とコントロールキーで押して対象選択してから右クリックするとサンプルでは1,2,3,8,5と表示される。)   MyItemのプロパティを変更するだけなら   MessageBox.Show(string.Join(",", items.Select(item => item.Index)));   であった部分を   items.ForEach(item => item.IsSelected = true);   とするだけでよいでしょうし、選択済みリストを作成する場合には   items.ToList() とするだけで別のコレクションにできます。 必要なら再ソートします。 で、これを次の処理にパスすればいいです。 
haru666

2016/12/15 02:26

んん…やりたいことを勘違いしていたかもしれません。 選択すること自体を実行したいってことですね。 すみません、これについては仮想化を止める以外の方法を知らないので即答できません。   DataGridの仮想化を止める方法についても書いておきます。 これをすると行数が大量にある場合は動作が遅くなることは留意しておいてください。 DataGridのプロパティに下記を追加してください。   VirtualizingStackPanel.IsVirtualizing="False"   これでItemContainerGenerator.ContainerFromIndex()はnullを返してこなくなるはずです。 この場合描画範囲外の部分についてもDependencyObjectを取得できますので、IsSelectedプロパティをtrueにしてあげてください。   通常範囲選択は標準で実行できるので質問の意味を取り違えていました。申し訳ないです。
退会済みユーザー

退会済みユーザー

2016/12/15 05:06

ありがとうございました。 少し勘違いされていたみたいですが回答としてはとても参考になりました。 やはり仮想化をoffにする方法はパフォーマンス的に厳しかったのですが、無事仮想化のままでやりたいことを行えました! ありがとうございます!
haru666

2016/12/15 05:11

やりたいことができたのならよかったです:-)
guest

0

これを呼ぶのではダメなのでしょうか?

DataGrid全選択

投稿2016/12/12 06:13

mugicya

総合スコア1046

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

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

退会済みユーザー

退会済みユーザー

2016/12/12 06:22

全選択ではなく複数選択なので指定範囲内の選択が行いたいのです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問