[wpf] WPF DataGrid에서 한 번 클릭 확인란을 선택하는 방법은 무엇입니까?

첫 번째 열이 텍스트 열이고 두 번째 열이 CheckBox 열인 DataGrid가 있습니다. 확인란을 클릭하면 원하는 것입니다. 확인해야합니다.

그러나 선택하려면 두 번의 클릭이 필요합니다. 첫 번째 클릭의 경우 셀이 선택되고 두 번째 클릭의 경우 확인란이 선택됩니다. 한 번의 클릭으로 확인란을 선택 / 선택 취소하는 방법.

WPF 4.0을 사용하고 있습니다. DataGrid의 열은 자동 생성됩니다.



답변

한 번의 클릭으로 DataGrid 확인란의 경우 일반 확인란 컨트롤을 내부에 DataGridTemplateColumn넣고 설정할 수 UpdateSourceTrigger=PropertyChanged있습니다.

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


답변

나는 다음 스타일로 이것을 해결했다.

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

물론 특정 열에 맞게이를 더 조정할 수 있습니다 …


답변

첫째, 나는 이것이 꽤 오래된 질문이라는 것을 알고 있지만 여전히 시도하고 답할 것이라고 생각했습니다.

나는 며칠 전에 같은 문제가 있었고 놀랍게도 짧은 해결책을 찾았습니다 ( 이 블로그 참조 ). 기본적으로 DataGridCheckBoxColumnXAML 의 정의를 다음으로 바꾸면됩니다.

<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 열광의 눈에 상태를 유지하는 데 도움이됩니다.).


답변

확인하려면 콘스탄틴 Salavatov의 응답 으로 작업을 AutoGenerateColumns받는 이벤트 처리기를 추가, 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자동 생성 된 모든 확인란 열을 “단일 클릭”으로 편집 할 수 있습니다.


답변

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;
    }


답변

나는이 제안들과 다른 사이트에서 찾은 많은 다른 것들을 시도했지만 그중 어느 것도 나를 위해 일하지 않았습니다. 결국 다음과 같은 솔루션을 만들었습니다.

내 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;
    }
}

이 모든 것이 무엇을합니까?

데이터 그리드에서 셀을 클릭 할 때마다 셀에 CheckBox 컨트롤이 포함되어 있는지 확인합니다. 이 경우 않습니다 , 우리는 그 체크 박스 초점을 설정합니다 그것의 가치 토글을 .

이것은 나에게 효과가있는 것으로 보이며 훌륭하고 쉽게 재사용 가능한 솔루션입니다.

이 작업을 수행하려면 코드를 작성 해야 한다는 점에 실망합니다 . WPF에서 행을 편집 모드로 전환하는 데 사용하기 때문에 첫 번째 마우스 클릭 (DataGrid의 CheckBox에서)이 “무시”된다는 설명은 논리적으로 들릴 수 있지만 실제 환경에서는 모든 실제 응용 프로그램의 작동 방식에 위배됩니다.

화면에 체크 박스가 표시되면 한 번 클릭하여 체크 / 체크 해제 할 수 있어야합니다. 이야기의 끝.


답변

여기에는 훨씬 간단한 해결책이 있습니다.

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

DataGridCheckBoxColumn구현 하는 데 사용 하는 경우 첫 번째 클릭은 초점을 맞추고 두 번째 클릭은 확인하는 것입니다.

그러나 DataGridTemplateColumn구현에 사용 하려면 한 번만 클릭하면됩니다.

사용 DataGridComboboxBoxColumn과 구현 의 차이점 DataGridTemplateColumn도 비슷합니다.