Флажок с DataGrid WPF



Я пытаюсь создать DataGrid в WPF 4.0 с помощью MVVM...



Требуемые функции -




  1. Muti-выбор строк с помощью флажка (один клик)

  2. a установите флажок все, чтобы проверить все флажки в datagrid


Что-то вроде этого -



Введите описание изображения здесь



Прошло 2 дня, и я не могу понять, как эффективно решить эту проблему..

Рабочий пример - это то, что мне нужно сейчас как можно скорее..



Я буду очень признателен, если у кого-то есть рабочее решение, чтобы поделиться со мной...



N пожалуйста, не говорите мне гуглить эту вещь, потому что ни одна из вещей не сработала для меня...



Обновление -




  1. я использую автогенерацию колонок

  2. я не хочу добавлять "IsSelected" или любое из таких свойств в мою модель..

  3. я просто столкнулся с 2 проблемами -


Во-первых, функция "Select all", то есть проверка всех флажков на флажке, щелчок которого присутствует в столбце. заголовок...(Я могу выбрать и отменить выбор datagrid, но не могу поставить / снять флажки)



Во-вторых, множественное выделение при щелчке мыши без удержания клавиши Ctrl..

868   3  

3 ответов:

Когда вы работаете с MVVM,вы должны знать, что считается данными, а что-строго пользовательским интерфейсом.

Будет ли ваш SelectedItems частью ваших данных или только вашим пользовательским интерфейсом?

Если это часть ваших данных, вы действительно должны иметь свойство IsSelected в вашей модели данных, даже если это означает расширение класса данных, чтобы включить свойство IsSelected, или создание класса-оболочки, который содержит только bool IsSelected и object MyDataItem. Первый вариант, вероятно, предпочтительнее, так как вы можете сохранить AutoGenerateColumns="True", и это упрощает привязку столбцов.

Тогда вы просто свяжете свой DataGridRow.SelectedItem со свойством IsSelected элемента данных:

<Style TargetType="{x:Type DataGridRow}">
    <Setter Property="IsSelected" Value="{Binding IsSelected}" />
</Style>
Но если ваш SelectedItems предназначен только для пользовательского интерфейса, или если вы по какой-то причине нарушаете шаблон MVVM в этом случае, то вы можете создать несвязанный CheckBox и использовать некоторый код позади, чтобы гарантировать, что CheckBox правильно синхронизирован с SelectedItem.

Я сделал быстрый пример приложения, и вот как выглядел мой код:

Во-первых, я просто добавил несвязанный столбец CheckBox в список столбцов с помощью DataGridTemplateColumn. Это будет добавлено перед списком столбцов AutoGenerateColumns.

<DataGrid x:Name="TestDataGrid" ItemsSource="{Binding Test}" 
          SelectionMode="Extended" CanUserAddRows="False"
          PreviewMouseLeftButtonDown="TestDataGrid_PreviewMouseLeftButtonDown_1">
    <DataGrid.Columns>
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <CheckBox x:Name="TestCheckBox"
                              PreviewMouseLeftButtonDown="CheckBox_PreviewMouseLeftButtonDown" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>
Во-вторых, я добавил событие PreviewMouseDown к CheckBox, чтобы оно установило свойство IsSelected строки.
private void CheckBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    var chk = (CheckBox)sender;
    var row = VisualTreeHelpers.FindAncestor<DataGridRow>(chk);
    var newValue = !chk.IsChecked.GetValueOrDefault();

    row.IsSelected = newValue;
    chk.IsChecked = newValue;

    // Mark event as handled so that the default 
    // DataGridPreviewMouseDown doesn't handle the event
    e.Handled = true;
}

Он должен перемещаться по VisualTree, чтобы найти DataGridRow, связанный с нажатой CheckBox, Чтобы выбрать его, и чтобы облегчить жизнь, я использую некоторые пользовательские VisualTreeHelpers, которые у меня есть в моем блоге, чтобы найти DataGridRow. Вы можете использовать то же самое код, или вы можете создать свой собственный метод для поиска VisualTree.

И последнее, если пользователь нажимает на любое другое место, кроме CheckBox, мы хотим отключить событие выбора по умолчанию DataGrid. Это гарантирует, что значение IsSelected изменится только при нажатии на CheckBox.

Есть несколько способов сделать это, которые отключат выбор на разных уровнях, но чтобы упростить жизнь, я просто отключил событие DataGrid.PreviewMouseLeftButtonDown, если пользователь не нажал на кнопку. CheckBox.

private void TestDataGrid_PreviewMouseLeftButtonDown_1(object sender, MouseButtonEventArgs e)
{
    var chk = VisualTreeHelpers.FindAncestor<CheckBox>((DependencyObject)e.OriginalSource, "TestCheckBox");

    if (chk == null)
        e.Handled = true;
}

Я снова использую свой пользовательский VisualTreeHelpers для навигации по визуальному дереву и выяснения, был ли установлен флажок, и отмены события, если пользователь щелкнул в любом другом месте, кроме CheckBox.

Что касается вашего 2-го запроса на добавление CheckBox к SelectAll или UnselectAll элементам, это снова будет зависеть от того, является ли ваш выбор частью пользовательского интерфейса или данных.

Если это часть пользовательского интерфейса, просто добавьте CheckBox к DataGridTemplateColumn.HeaderTemplate, и когда это щелкнув, выполните цикл по DataGrid.Rows, найдите CheckBox в первом столбце и установите или снимите флажок.

Если это часть данных, вы можете сделать то же самое (только установить привязанное значение в DataGrid.Items вместо CheckBox.IsChecked из DataGrid.Rows), или вы можете сделать так, как предложил Адольфо Перес, и привязать его к свойству на ViewModel.

Для решения MVVM вы можете попробовать следующее:

    <StackPanel>
    <DataGrid ItemsSource="{Binding Path=TestItems}" AutoGenerateColumns="False" Name="MyDataGrid"
              CanUserAddRows="False">
        <DataGrid.Columns>
            <DataGridCheckBoxColumn Binding="{Binding IsSelected}" Width="50" >
                <DataGridCheckBoxColumn.HeaderTemplate>
                    <DataTemplate x:Name="dtAllChkBx">
                        <CheckBox Name="cbxAll" Content="All" IsChecked="{Binding Path=DataContext.AllSelected,RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
                    </DataTemplate>
                </DataGridCheckBoxColumn.HeaderTemplate>
            </DataGridCheckBoxColumn>
            <DataGridTemplateColumn Header="Name" Width="SizeToCells" IsReadOnly="True">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Name}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
</StackPanel>

В вашем ViewModel:

private void PopulateTestItems()
        {
            TestItems = new ObservableCollection<TestItem>();
            for (int i = 0; i < 5; i++)
            {
                TestItem ti = new TestItem();
                ti.Name = "TestItem" + i;
                ti.IsSelected = true;
                TestItems.Add(ti);
            }
        }

        private bool _AllSelected;
        public bool AllSelected
        {
            get { return _AllSelected; }
            set
            {
                _AllSelected = value;
                TestItems.ToList().ForEach(x => x.IsSelected = value);
                NotifyPropertyChanged(m => m.AllSelected);
            }
        }

    private ObservableCollection<TestItem> _TestItems;
    public ObservableCollection<TestItem> TestItems
    {
        get { return _TestItems; }
        set
        {
            _TestItems = value;
            NotifyPropertyChanged(m => m.TestItems);
        }
    }

И, наконец, пример класса модели:

public class TestItem : ModelBase<TestItem>
{
    private string _Name;
    public string Name
    {
        get { return _Name; }
        set
        {
            _Name = value;
            NotifyPropertyChanged(m => m.Name);
        }
    }
    private bool _IsSelected;
    public bool IsSelected
    {
        get { return _IsSelected; }
        set
        {
            _IsSelected = value;
            NotifyPropertyChanged(m => m.IsSelected);
        }
    }
}

Большая часть кода выше должна быть понятна, но если у вас есть какие-либо вопросы, дайте мне знать

Ваш взгляд может быть чем-то вроде

    <DataGrid Name="SomeDataGrid" Grid.Row="0" ItemsSource="{Binding Path=SomeCollection}">
            <DataGrid.Columns>
            <DataGridTemplateColumn>
            <DataGridTemplateColumn.HeaderTemplate>
    <DataTemplate>
        <CheckBox IsChecked="{Binding
            RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
            Path=DataContext.AllItemsAreChecked}" />
    </DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate DataType="{x:Type local:SomeType}">
                            <CheckBox Focusable="False" IsChecked="{Binding Path=IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"  
                                      HorizontalAlignment="Left" VerticalAlignment="Center"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>

                <DataGridTemplateColumn Header="RandomNumber" Width="160">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate DataType="{x:Type local:SomeType}">
                            <TextBlock Text="{Binding Path=RandomNumber}" TextWrapping="Wrap"  HorizontalAlignment="Left" VerticalAlignment="Center"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTemplateColumn Header="Date" Width="160">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate DataType="{x:Type local:SomeType}">
                            <TextBlock Text="{Binding Path=Date}" TextWrapping="Wrap"  HorizontalAlignment="Left" VerticalAlignment="Center"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTemplateColumn Header="Time" Width="50">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate DataType="{x:Type local:SomeType}">


                                    <TextBlock Text="{Binding Time}" HorizontalAlignment="Left" VerticalAlignment="Center"/>


                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>                    

            </DataGrid.Columns>
        </DataGrid>

И в viewmodel Свойство привязки SomeCollection является наблюдаемым sometype содержит такие свойства, как IsSelected, RandomNumber, Date, Time

Например:

    class ViewModel
    {
      public ObservableCollection<SomeType> SomeCollection{get;set;}
    }

    class SomeType
    {
       public string Date {get;set;}
       public string Time {get;set;}
       public string RandomNumber {get;set;}
       public bool IsSelected {get;set;}
    }

Comments

    Ничего не найдено.