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

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

新規登録して質問してみよう
ただいま回答率
85.35%
DataGrid

GUIの一種であり、データを表の形式でみることが可能です。

WPF

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

Q&A

1回答

7828閲覧

DataGrid 選択解除とフォーカスの協調

m_rase

総合スコア8

DataGrid

GUIの一種であり、データを表の形式でみることが可能です。

WPF

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

0グッド

0クリップ

投稿2021/05/08 06:49

前提・実現したいこと

1)DataGridの選択状態をボタンを押して、ViewModelから選択する前の状態にしたい。
2)DataGrid内のTextBoxやチェックboxを選択した時でも、IsFocused="true"と同じ状態にしたい。

参考になるサイトまたはコードをご存知の方いましたらご教示していただきたいです。
よろしくお願い致します。

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

1)選択が解除できず、ずっとGrayのスタイルが残る
2)TextBoxを選択、☑を操作した時に、LightGrayにならない。

該当のソースコード

XAML

1<UserControl x:Class="DataGrid0508.Views.DataGridView" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:DataGrid0508.Views" 7 xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors" 8 xmlns:l="http://schemas.livet-mvvm.net/2011/wpf" 9 xmlns:v="clr-namespace:DataGrid0508.Views" 10 xmlns:vm="clr-namespace:DataGrid0508.ViewModels" 11 mc:Ignorable="d" 12 d:DesignHeight="450" d:DesignWidth="800"> 13 <UserControl.DataContext> 14 <vm:DataGridViewModel /> 15 </UserControl.DataContext> 16 <Grid> 17 <Grid.RowDefinitions> 18 <RowDefinition Height="50"/> 19 <RowDefinition/> 20 <RowDefinition Height="50"/> 21 </Grid.RowDefinitions> 22 23 <Button Content="選択解除" Width="100" Margin="5" HorizontalAlignment="Left"> 24 <behaviors:Interaction.Triggers> 25 <behaviors:EventTrigger EventName="PreviewMouseLeftButtonDown"> 26 <l:LivetCallMethodAction MethodName="TestButton" MethodTarget="{Binding}" /> 27 </behaviors:EventTrigger> 28 </behaviors:Interaction.Triggers> 29 </Button> 30 <DataGrid Grid.Row="1" ItemsSource ="{Binding MyList}"> 31 <DataGrid.CellStyle> 32 <Style TargetType="DataGridCell"> 33 <Setter Property="Height" Value="20"/> 34 <Style.Triggers> 35 <Trigger Property="IsSelected" Value="True"> 36 <Setter Property="Height" Value="40" /> 37 <Setter Property="Background" Value="Gray"/> 38 </Trigger> 39 <Trigger Property="IsFocused" Value="True"> 40 <Setter Property="Background" Value="LightGray"/> 41 </Trigger> 42 </Style.Triggers> 43 </Style> 44 </DataGrid.CellStyle> 45 46 <DataGrid.Columns> 47 <DataGridTemplateColumn Width="100"> 48 <DataGridTemplateColumn.CellTemplate> 49 <DataTemplate> 50 <StackPanel Orientation="Horizontal"> 51 <TextBox Text="コメント" Width="50"/> 52 <TextBlock Text="○"/> 53 </StackPanel> 54 </DataTemplate> 55 </DataGridTemplateColumn.CellTemplate> 56 </DataGridTemplateColumn> 57 </DataGrid.Columns> 58 </DataGrid> 59 60 61 </Grid> 62</UserControl>

C#

1 2namespace DataGrid0508.ViewModels 3{ 4 public class DataGridViewModel:ViewModel 5 { 6 public DataGridViewModel() 7 { 8 MyList = new ObservableCollection<Person>( 9 10 Enumerable.Range(1, 5).Select(i => new Person 11 { 12 Name = "田中" + i, 13 Age = 20 + i, 14 AuthMember = i % 2 == 0 15 })); 16 } 17 18 19 private ObservableCollection<Person> _MyList; 20 21 public ObservableCollection<Person> MyList 22 { 23 get 24 { return _MyList; } 25 set 26 { 27 if (_MyList == value) 28 return; 29 _MyList = value; 30 RaisePropertyChanged(); 31 } 32 } 33 34 public void TestButton() 35 { 36 //選択解除 37 } 38 39 40 } 41} 42public class Person 43{ 44 public string Name { get; set; } 45 public int Age { get; set; } 46 public bool AuthMember { get; set; } 47}

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

VisualStudio2019

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

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

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

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

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

guest

回答1

0

1)選択が解除できず、ずっとGrayのスタイルが残る

MoveCurrentToPosition(-1)でもすればいいんじゃないですかね?
CollectionView.MoveCurrentToPosition(Int32) メソッド (System.Windows.Data) | Microsoft Docs

ApplicationCommands.SelectAll プロパティ (System.Windows.Input) | Microsoft Docs
との対称性を考えてRoutedCommandにしてみました。
Viewで完結するのがいい点ですが、ViewModelでどうこうしたい場合は逆に扱いにくいです^^;

2)TextBoxを選択、☑を操作した時に、LightGrayにならない。

フォーカスがTextBoxCheckBoxに行きますから当然そうなりますね。
SelectionUnit="Cell"でいいならこんな感じで行けましたがどうでしょうか。

参考
wpf - DataGrid SelectionUnit=Cell disables all support for a selected row? - Stack Overflow

xml

1<Window 2 x:Class="Questions337191.Views.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:b="http://schemas.microsoft.com/xaml/behaviors" 6 xmlns:v="clr-namespace:Questions337191.Views" 7 xmlns:vm="clr-namespace:Questions337191.ViewModels" 8 Width="525" 9 Height="350"> 10 <Window.DataContext> 11 <vm:MainWindowViewModel /> 12 </Window.DataContext> 13 <DockPanel> 14 <!-- 15 メニューから呼ぶとなぜか激重になる。 16 以降ボタンから呼んでもDataGridの左上ボタンでも同じく激重。 17 意味が分からないw 18 --> 19 <!--<Menu DockPanel.Dock="Top"> 20 <MenuItem Header="編集"> 21 <MenuItem Command="ApplicationCommands.SelectAll" CommandTarget="{Binding ElementName=dataGrid}" /> 22 <MenuItem Command="v:DataGridBehavior.UnselectAll" CommandTarget="{Binding ElementName=dataGrid}" /> 23 </MenuItem> 24 </Menu>--> 25 <Grid> 26 <Grid.RowDefinitions> 27 <RowDefinition Height="Auto" /> 28 <RowDefinition /> 29 </Grid.RowDefinitions> 30 <StackPanel Orientation="Horizontal"> 31 <Button 32 MinWidth="100" 33 Margin="5" 34 Command="ApplicationCommands.SelectAll" 35 CommandTarget="{Binding ElementName=dataGrid}" 36 Content="すべて選択" /> 37 <Button 38 MinWidth="100" 39 Margin="5" 40 Command="v:DataGridBehavior.UnselectAll" 41 CommandTarget="{Binding ElementName=dataGrid}" 42 Content="選択解除" /> 43 </StackPanel> 44 45 <DataGrid 46 x:Name="dataGrid" 47 Grid.Row="1" 48 ItemsSource="{Binding MyList}" 49 SelectionUnit="Cell"> 50 <b:Interaction.Behaviors> 51 <v:DataGridBehavior /> 52 </b:Interaction.Behaviors> 53 <DataGrid.RowStyle> 54 <Style TargetType="DataGridRow"> 55 <Setter Property="Height" Value="20" /> 56 <Style.Triggers> 57 <Trigger Property="v:DataGridAttachedProperties.IsCellSelected" Value="True"> 58 <Setter Property="Height" Value="40" /> 59 <Setter Property="Background" Value="Gray" /> 60 </Trigger> 61 </Style.Triggers> 62 </Style> 63 </DataGrid.RowStyle> 64 65 <DataGrid.CellStyle> 66 <Style TargetType="DataGridCell"> 67 <Style.Triggers> 68 <Trigger Property="IsSelected" Value="True"> 69 <Setter Property="Background" Value="LightGray" /> 70 <Setter Property="v:DataGridAttachedProperties.IsCellSelected" Value="True" /> 71 </Trigger> 72 <Trigger Property="IsSelected" Value="False"> 73 <Setter Property="v:DataGridAttachedProperties.IsCellSelected" Value="False" /> 74 </Trigger> 75 </Style.Triggers> 76 </Style> 77 </DataGrid.CellStyle> 78 79 <DataGrid.Columns> 80 <DataGridTemplateColumn Width="100"> 81 <DataGridTemplateColumn.CellTemplate> 82 <DataTemplate> 83 <StackPanel Orientation="Horizontal"> 84 <TextBox Text="コメント" /> 85 <TextBlock Text="" /> 86 </StackPanel> 87 </DataTemplate> 88 </DataGridTemplateColumn.CellTemplate> 89 </DataGridTemplateColumn> 90 </DataGrid.Columns> 91 </DataGrid> 92 </Grid> 93 </DockPanel> 94</Window>

cs

1using Livet; 2using System.Collections.ObjectModel; 3using System.Linq; 4 5namespace Questions337191.ViewModels 6{ 7 public class MainWindowViewModel : ViewModel 8 { 9 public ObservableCollection<Person> MyList { get; } 10 11 public MainWindowViewModel() 12 { 13 MyList = new ObservableCollection<Person>( 14 Enumerable.Range(1, 10_000).Select(i => new Person 15 { 16 Name = "田中" + i, 17 Age = 20 + i, 18 AuthMember = i % 2 == 0, 19 })); 20 } 21 } 22 23 public class Person 24 { 25 public string Name { get; set; } 26 public int Age { get; set; } 27 public bool AuthMember { get; set; } 28 } 29}

cs

1using Microsoft.Xaml.Behaviors; 2using System.Linq; 3using System.Windows; 4using System.Windows.Controls; 5using System.Windows.Input; 6using System.Windows.Media; 7 8namespace Questions337191.Views 9{ 10 // [wpf - DataGrid SelectionUnit=Cell disables all support for a selected row? - Stack Overflow](https://stackoverflow.com/questions/9489041/datagrid-selectionunit-cell-disables-all-support-for-a-selected-row) 11 public static class DataGridAttachedProperties 12 { 13 public static bool GetIsCellSelected(DependencyObject obj) => (bool)obj.GetValue(IsCellSelectedProperty); 14 public static void SetIsCellSelected(DependencyObject obj, bool value) => obj.SetValue(IsCellSelectedProperty, value); 15 public static readonly DependencyProperty IsCellSelectedProperty 16 = DependencyProperty.RegisterAttached("IsCellSelected", typeof(bool), typeof(DataGridAttachedProperties), 17 new UIPropertyMetadata(false, OnIsCellSelectedChanged)); 18 private static void OnIsCellSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 19 { 20 if (d is DataGridCell cell) 21 { 22 var row = FindVisualParent<DataGridRow>(cell); 23 24 // 同じ行内で複数選択がある状態でそのうち1つを選択し直した場合 25 // そのセルはCellSelectedChangedが出ない(選択状態は変わらない)ので 26 // 周りの選択解除だけ伝わってしまいバグる 27 //row.SetValue(IsCellSelectedProperty, e.NewValue); 28 29 // しかたがないので行内全走査 30 // 重そうだが100桁くらいなら気にならなかった(1000桁あると数秒止まった^^; 31 var p = FindVisualParent<DataGridCellsPanel>(cell); 32 var b = p.Children.Cast<DataGridCell>().Any(x => x.IsSelected); 33 row.SetValue(IsCellSelectedProperty, b); 34 } 35 } 36 37 private static T FindVisualParent<T>(DependencyObject child) where T : DependencyObject 38 { 39 var parentObject = VisualTreeHelper.GetParent(child); 40 if (parentObject == null) return null; 41 if (parentObject is T parent) return parent; 42 else return FindVisualParent<T>(parentObject); 43 } 44 } 45 46 public class DataGridBehavior : Behavior<DataGrid> 47 { 48 public static readonly RoutedUICommand UnselectAll = new RoutedUICommand("選択解除", "UnselectAll", typeof(DataGridBehavior)); 49 50 protected override void OnAttached() 51 { 52 base.OnAttached(); 53 var commandBinding = new CommandBinding(UnselectAll, Executed); 54 AssociatedObject.CommandBindings.Add(commandBinding); 55 } 56 57 protected override void OnDetaching() 58 { 59 base.OnDetaching(); 60 AssociatedObject.CommandBindings.Clear(); 61 } 62 63 private void Executed(object target, ExecutedRoutedEventArgs e) 64 { 65 if (AssociatedObject.SelectionUnit == DataGridSelectionUnit.FullRow) 66 AssociatedObject.UnselectAll(); 67 else 68 AssociatedObject.UnselectAllCells(); 69 e.Handled = true; 70 } 71 } 72}

あれこれいじっていたらいろいろバグを見つけてしまいました^^;

  • DataGridAttachedProperties複数選択時未考慮
    回答コードを参照してください。
  • MenuContextMenuDataGridSelectAllを使うと以降激重
    SelectAllだけの(Style等をすべてなくして追加コードが一切ない)状態でも再現しますので、WPFのバグっぽいです(意味が分からな過ぎて原因も回避法もわかりません^^;

投稿2021/05/08 10:31

編集2023/07/27 13:35
TN8001

総合スコア9862

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

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

m_rase

2021/05/10 14:12

回答頂きありがとうございます。 返事が遅く、申し訳ありません。 2)については、教えて頂いた方法で出来ました。ありがとうございます。 1)について、起動直後の、どのRowも選択されていない状態。にしたいのですが、方法、参考があれば教えて頂けないでしょうか。 説明が分かり難くすみません。
TN8001

2021/05/10 15:01

失礼しました。確認不足でした。 行選択でないとMoveCurrentToPositionは効かないんですね。。 DataGridを渡せばUnselectAllCellsできるのですが、MVVM的にはイヤですね^^; <Button Width="100" Margin="5" HorizontalAlignment="Left" Command="{Binding UnselectCommand}" CommandParameter="{Binding ElementName=dataGrid}" Content="選択解除" /> <DataGrid x:Name="dataGrid" UnselectCommand = new ListenerCommand<DataGrid>(x => x.UnselectAllCells()); ほかに何かないか調べてみます。
m_rase

2021/05/12 11:24

回答ありがとうございます。 Viewから実行する方法。VMにDataGrid渡して実施する方法。の教えて頂いた方法でイメージの動作が出来ました。ありがとうございます。 お手数で申し訳ありませんが、VMから実施する方法があれば、教えて頂きたいです。
TN8001

2021/05/12 11:30

「VMから実施する方法」というのは 2021/05/11 00:01 のコメントの詳細コードという意味ですか? それとも 1) Viewから実行する方法 2) VMにDataGrid渡して実施する方法 3) VMから実施する方法 のような第3の案という意味ですか??
m_rase

2021/05/12 14:44

3)のような第3の案という意味でした。分かり難くすみません。 ______ 3)VMから実施する方法。 日付が変わった事をVMで確認して、日付変更後はVMからDataGridを未選択な状態にしたい。 Viewは操作しない。 今の理解。 1)Viewから実行する方法 Viewのボタン。  Command="v:DataGridBehavior.UnselectAll"  CommandTarget="{Binding ElementName=dataGrid}" 2)VMにDataGrid渡して実施する方法 VMに(DataGrid)渡して、grid.UnselectAllCells();
TN8001

2021/05/12 15:03

一番素直?なのは「SelectedCellsをバインドできるようにする」でしょうか。 選択解除するにはVMからそれをクリアする。 試していませんが、このようなもの。 [WPF Datagrid: MVVM friendly way to bind SelectedCells to my ViewModel - Stack Overflow](https://stackoverflow.com/questions/4714758/wpf-datagrid-mvvm-friendly-way-to-bind-selectedcells-to-my-viewmodel しかし選択解除がしたいだけなら、簡略化してIsSelectedのようなbool値だけでいいと思います。 VMからIsSelected=trueした時に、どう動くのがいいのかわかりませんが^^;
TN8001

2021/05/12 15:28

それとも 検索キーワード「viewmodelからviewを操作」 みたいなことをおっしゃっているのかな? この辺はそれぞれMVVMこだわり度でだいぶ変わってきますので、お好きにどうぞとしか言えないですね。。。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問