web-dev-qa-db-ja.com

WPF DataGridでシングルクリックチェックボックス選択を実行するにはどうすればよいですか?

最初の列がテキスト列、2番目の列がCheckBox列のDataGridがあります。私が欲しいのは、チェックボックスをクリックした場合です。チェックされるはずです。

ただし、選択するには2回クリックします。最初のクリックではセルが選択され、2回目のクリックではチェックボックスがオンになります。ワンクリックでチェックボックスをオン/オフにする方法。

WPF 4.0を使用しています。 DataGridの列は自動生成されます。

128
Prince Ashitaka

シングルクリックDataGridチェックボックスの場合、DataGridTemplateColumn内に通常のチェックボックスコントロールを配置して、UpdateSourceTrigger=PropertyChangedを設定するだけです。

<DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <CheckBox IsChecked="{Binding Path=IsSelected, UpdateSourceTrigger=PropertyChanged}" />
    </DataTemplate>
</DataGridTemplateColumn.CellTemplate>
171

これを次のスタイルで解決しました:

<Style TargetType="DataGridCell">
     <Style.Triggers>
         <Trigger Property="IsMouseOver" Value="True">
             <Setter Property="IsEditing" Value="True" />
         </Trigger>
     </Style.Triggers>
 </Style>

もちろん、これを特定の列にさらに適応させることは可能です...

56
Jim Adorno

まず、これはかなり古い質問であることは知っていますが、それでも試して答えたいと思っていました。

数日前に同じ問題を抱えていましたが、驚くほど短い解決策に出会いました( このブログ を参照)。基本的に、必要なことは、XAMLのDataGridCheckBoxColumn定義を次のものに置き換えることだけです。

<DataGridTemplateColumn Header="MyCheckBoxColumnHeader">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" IsChecked="{Binding Path=MyViewModelProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

このソリューションの利点は明らかです-XAMLのみです。したがって、追加のUIロジックでコードバックに負担をかけることを効果的に控え、MVVMの熱狂者の目であなたのステータスを維持するのに役立ちます;)。

21
Priidu Neemre

Goblinの回答で参照されているブログに基づいていますが、.NET 4.0および行選択モードで動作するように変更されています。

編集モードに入り、シングルクリックまたはテキスト入力でドロップダウンを表示することにより、DataGridComboBoxColumnの編集も高速化されることに注意してください。

XAML:

        <Style TargetType="{x:Type DataGridCell}">
            <EventSetter Event="PreviewMouseLeftButtonDown" Handler="DataGridCell_PreviewMouseLeftButtonDown" />
            <EventSetter Event="PreviewTextInput" Handler="DataGridCell_PreviewTextInput" />
        </Style>

コードビハインド:

    private void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        DataGridCell cell = sender as DataGridCell;
        GridColumnFastEdit(cell, e);
    }

    private void DataGridCell_PreviewTextInput(object sender, TextCompositionEventArgs e)
    {
        DataGridCell cell = sender as DataGridCell;
        GridColumnFastEdit(cell, e);
    }

    private static void GridColumnFastEdit(DataGridCell cell, RoutedEventArgs e)
    {
        if (cell == null || cell.IsEditing || cell.IsReadOnly)
            return;

        DataGrid dataGrid = FindVisualParent<DataGrid>(cell);
        if (dataGrid == null)
            return;

        if (!cell.IsFocused)
        {
            cell.Focus();
        }

        if (cell.Content is CheckBox)
        {
            if (dataGrid.SelectionUnit != DataGridSelectionUnit.FullRow)
            {
                if (!cell.IsSelected)
                    cell.IsSelected = true;
            }
            else
            {
                DataGridRow row = FindVisualParent<DataGridRow>(cell);
                if (row != null && !row.IsSelected)
                {
                    row.IsSelected = true;
                }
            }
        }
        else
        {
            ComboBox cb = cell.Content as ComboBox;
            if (cb != null)
            {
                //DataGrid dataGrid = FindVisualParent<DataGrid>(cell);
                dataGrid.BeginEdit(e);
                cell.Dispatcher.Invoke(
                 DispatcherPriority.Background,
                 new Action(delegate { }));
                cb.IsDropDownOpen = true;
            }
        }
    }


    private static T FindVisualParent<T>(UIElement element) where T : UIElement
    {
        UIElement parent = element;
        while (parent != null)
        {
            T correctlyTyped = parent as T;
            if (correctlyTyped != null)
            {
                return correctlyTyped;
            }

            parent = VisualTreeHelper.GetParent(parent) as UIElement;
        }
        return null;
    }
16
surfen

Konstantin Salavatov's answerAutoGenerateColumnsを使用するには、次のコードを使用してDataGridAutoGeneratingColumnにイベントハンドラーを追加します。

if (e.Column is DataGridCheckBoxColumn && !e.Column.IsReadOnly)
{
    var checkboxFactory = new FrameworkElementFactory(typeof(CheckBox));
    checkboxFactory.SetValue(FrameworkElement.HorizontalAlignmentProperty, HorizontalAlignment.Center);
    checkboxFactory.SetValue(FrameworkElement.VerticalAlignmentProperty, VerticalAlignment.Center);
    checkboxFactory.SetBinding(ToggleButton.IsCheckedProperty, new Binding(e.PropertyName) { UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });

    e.Column = new DataGridTemplateColumn
        {
            Header = e.Column.Header,
            CellTemplate = new DataTemplate { VisualTree = checkboxFactory },
            SortMemberPath = e.Column.SortMemberPath
        };
}

これにより、DataGridのすべての自動生成チェックボックス列が「シングルクリック」編集可能になります。

15
Allon Guralnek

私はこれらの提案、および他のサイトで見つけた他の多くの提案を試しましたが、それらのどれも私のために全く働きませんでした。最後に、次のソリューションを作成しました。

独自のDataGrid継承コントロールを作成し、次のコードを追加しました。

public class DataGridWithNavigation : Microsoft.Windows.Controls.DataGrid
{
    public DataGridWithNavigation()
    {
        EventManager.RegisterClassHandler(typeof(DataGridCell), 
            DataGridCell.PreviewMouseLeftButtonDownEvent,
            new RoutedEventHandler(this.OnPreviewMouseLeftButtonDown));
    }


    private void OnPreviewMouseLeftButtonDown(object sender, RoutedEventArgs e)
    {
        DataGridCell cell = sender as DataGridCell;
        if (cell != null && !cell.IsEditing && !cell.IsReadOnly)
        {
          DependencyObject obj = FindFirstControlInChildren(cell, "CheckBox");
            if (obj != null)
            {
                System.Windows.Controls.CheckBox cb = (System.Windows.Controls.CheckBox)obj;
                cb.Focus();
                cb.IsChecked = !cb.IsChecked;
            }
        }
    }

    public DependencyObject FindFirstControlInChildren(DependencyObject obj, string controlType)
    {
        if (obj == null)
            return null;

        // Get a list of all occurrences of a particular type of control (eg "CheckBox") 
        IEnumerable<DependencyObject> ctrls = FindInVisualTreeDown(obj, controlType);
        if (ctrls.Count() == 0)
            return null;

        return ctrls.First();
    }

    public IEnumerable<DependencyObject> FindInVisualTreeDown(DependencyObject obj, string type)
    {
        if (obj != null)
        {
            if (obj.GetType().ToString().EndsWith(type))
            {
                yield return obj;
            }

            for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                foreach (var child in FindInVisualTreeDown(VisualTreeHelper.GetChild(obj, i), type))
                {
                    if (child != null)
                    {
                        yield return child;
                    }
                }
            }
        }
        yield break;
    }
}

これはすべて何をしますか?

さて、DataGridのセルをクリックするたびに、セルにCheckBoxコントロールが含まれているかどうかがわかります。 doesの場合、フォーカスをそのCheckBoxに設定しますおよびその値を切り替えます

これは私にとってはうまくいくようで、簡単に再利用できるニースのソリューションです。

必要これを行うためのコードを書くことは残念です。 (DataGridのCheckBoxでの)最初のマウスクリックはWPFを使用して行を編集モードにするため「無視」されるという説明は論理的に聞こえるかもしれませんが、実際には、これはすべての実際のアプリケーションの動作に反します。

画面にチェックボックスが表示されている場合、ユーザーは一度クリックしてチェックを外すことができます。物語の終わり。

9
Mike Gledhill

ここにはもっと簡単な解決策があります。

          <DataGridTemplateColumn MinWidth="20" >
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Grid>
                            <CheckBox VerticalAlignment="Center" HorizontalAlignment="Center"/>
                        </Grid>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

DataGridCheckBoxColumnを使用して実装する場合、最初のクリックはフォーカス、2番目のクリックはチェックです。

ただし、DataGridTemplateColumnを使用して実装するには、ワンクリックで済みます。

DataGridComboboxBoxColumnの使用とDataGridTemplateColumnによる実装の違いも同様です。

8
Weidian Huang

私はこれで解決しました:

<DataGridTemplateColumn>
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <Viewbox Height="25">
                <CheckBox IsChecked="{Binding TheProperty, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
            </Viewbox>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

シングルクリックでアクティブなチェックボックス!

8

Jim Adorno彼の投稿に対する回答とコメントに基づいて、これはMultiTriggerを使用したソリューションです。

<Style TargetType="DataGridCell">
  <Style.Triggers>
    <MultiTrigger>
      <MultiTrigger.Conditions>
    <Condition Property="IsReadOnly" Value="False" />
    <Condition Property="IsMouseOver" Value="True" />
      </MultiTrigger.Conditions>
      <Setter Property="IsEditing" Value="True" />
    </MultiTrigger>
  </Style.Triggers>
</Style>
6
Rafal Spacjer

さらに別の簡単な解決策は、このスタイルをDataGridColumnに追加することです。スタイルの本文は空にすることができます。

<DataGridCheckBoxColumn>
     <DataGridCheckBoxColumn.ElementStyle>
          <Style TargetType="CheckBox">
           </Style>
     </DataGridCheckBoxColumn.ElementStyle>
</DataGridCheckBoxColumn>
5
<Style x:Key="StilCelula" TargetType="DataGridCell"> 
<Style.Triggers>
 <Trigger Property="IsMouseOver" Value="True">
   <Setter Property="IsEditing" 
     Value="{Binding RelativeSource={x:Static RelativeSource.Self}, 
     Converter={StaticResource CheckBoxColumnToEditingConvertor}}" />
 </Trigger>
</Style.Triggers>
<Style>
Imports System.Globalization
Public Class CheckBoxColumnToEditingConvertor
    Implements IValueConverter
    Public Function Convert(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As CultureInfo) As Object Implements IValueConverter.Convert
        Try

            Return TypeOf TryCast(value, DataGridCell).Column Is DataGridCheckBoxColumn
        Catch ex As Exception
            Return Visibility.Collapsed
        End Try
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
        Throw New NotImplementedException()
    End Function
End Class
1
TotPeRo