c# doc - MVVM WPF 프로젝트의 DataGrid에서 여러 항목 선택




windows presentation (8)

MVVM WPF 프로젝트의 DataGrid 에서 여러 항목을 선택하려면 어떻게합니까?


Answers

WPF의 기본 DataGrid 에서는 Binding을 사용할 수 없으므로 SelectedItem -Property를 사용할 수 있으므로 SelectedItems -Property가 DependencyProperty가 아닙니다.

한 가지 방법은 DataGrid의 SelectionChanged -Event를 등록하여 선택한 항목을 저장하는 ViewModel의 속성을 업데이트하는 것입니다.

DataGrid의 SelectedItems 속성은 IList 형식이므로 목록의 항목을 특정 형식으로 캐스팅해야합니다.

기음#

public MyViewModel {
  get{
    return this.DataContext as MyViewModel;
  }
}

private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) {
  // ... Get SelectedItems from DataGrid.
  var grid = sender as DataGrid;
  var selected = grid.SelectedItems;

  List<MyObject> selectedObjects = selected.OfType<MyObject>().ToList();

  MyViewModel.SelectedMyObjects = selectedObjects;
}

XAML

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
    <DataGrid
        SelectionChanged="DataGrid_SelectionChanged"
        />
    </Grid>
</Window>

이렇게하려면 사용자 지정 종속성 속성 을 추가하기 만하면됩니다.

public class CustomDataGrid : DataGrid
{
    public CustomDataGrid ()
    {
        this.SelectionChanged += CustomDataGrid_SelectionChanged;
    }

    void CustomDataGrid_SelectionChanged (object sender, SelectionChangedEventArgs e)
    {
        this.SelectedItemsList = this.SelectedItems;
    }
    #region SelectedItemsList

    public IList SelectedItemsList
    {
        get { return (IList)GetValue (SelectedItemsListProperty); }
        set { SetValue (SelectedItemsListProperty, value); }
    }

    public static readonly DependencyProperty SelectedItemsListProperty =
            DependencyProperty.Register ("SelectedItemsList", typeof (IList), typeof (CustomDataGrid), new PropertyMetadata (null));

    #endregion
}

이제이 dataGrid 를 XAML에서 사용할 수 있습니다.

<Window x:Class="DataGridTesting.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:local="clr-namespace:DataGridTesting.CustomDatagrid"
    Title="MainWindow"
    Height="350"
    Width="525">
  <DockPanel>
    <local:CustomDataGrid ItemsSource="{Binding Model}"
        SelectionMode="Extended"
        AlternatingRowBackground="Aquamarine"
        SelectionUnit="FullRow"
        IsReadOnly="True"
        SnapsToDevicePixels="True"
        SelectedItemsList="{Binding TestSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
  </DockPanel>
</Window>

ViewModel :

public class MyViewModel : INotifyPropertyChanged
{
    private static object _lock = new object ();
    private List<MyModel> _myModel;

    public IEnumerable<MyModel> Model { get { return _myModel; } }

    private IList _selectedModels = new ArrayList ();

    public IList TestSelected
    {
        get { return _selectedModels; }
        set
        {
            _selectedModels = value;
            RaisePropertyChanged ("TestSelected");
        }
    }

    public MyViewModel ()
    {
        _myModel = new List<MyModel> ();
        BindingOperations.EnableCollectionSynchronization (_myModel, _lock);

        for (int i = 0; i < 10; i++)
        {
            _myModel.Add (new MyModel
            {
                Name = "Test " + i,
                Age = i * 22
            });
        }
        RaisePropertyChanged ("Model");
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged (string propertyName)
    {
        var pc = PropertyChanged;
        if (pc != null)
            pc (this, new PropertyChangedEventArgs (propertyName));
    }
}

내 모델 :

public class MyModel
{
    public string Name { get; set; }
    public int Age { get; set; }
}

마지막으로 MainWindow 의 코드 숨김은 다음과 같습니다.

public partial class MainWindow : Window
{
    public MainWindow ()
    {
        InitializeComponent ();
        this.DataContext = new MyViewModel ();
    }
}

이 깨끗한 MVVM 디자인이 도움이되기를 바랍니다.


WPF DataGrid는 이것을 허용합니다. 단순히 DataGrid.Rows.SelectionMode 및 DataGrid.Rows.SelectionUnit을 각각 "Extended"및 "CellOrRowHeader"로 설정하십시오. 이 이미지는 Blend에서 수행 할 수 있습니다. 이렇게하면 사용자가 각 셀, 전체 행 등을 원하는만큼 많이 선택할 수 있습니다. Shift 또는 Ctrl 키를 사용하여 계속 선택할 수 있습니다.


내가해야 할 일은 System.Windows.Interactivity 사용하여 Behaviors 를 만드는 것입니다. 프로젝트에서 수동으로 참조해야합니다.

SelectedItems 노출시키지 않는 컨트롤 (ListBox, DataGrid)

다음과 같은 비헤이비어 클래스를 만들 수 있습니다.

public class ListBoxSelectedItemsBehavior : Behavior<ListBox>
{
    protected override void OnAttached()
    {
        AssociatedObject.SelectionChanged += AssociatedObjectSelectionChanged;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.SelectionChanged -= AssociatedObjectSelectionChanged;
    }

    void AssociatedObjectSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var array = new object[AssociatedObject.SelectedItems.Count];
        AssociatedObject.SelectedItems.CopyTo(array, 0);
        SelectedItems = array;
    }

    public static readonly DependencyProperty SelectedItemsProperty =
        DependencyProperty.Register("SelectedItems", typeof(IEnumerable), typeof(ListBoxSelectedItemsBehavior), 
        new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    public IEnumerable SelectedItems
    {
        get { return (IEnumerable)GetValue(SelectedItemsProperty); }
        set { SetValue(SelectedItemsProperty, value); }
    }
}

그리고 귀하의 XAML 나는 xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 이고 behaviorsBehavior 클래스의 네임 스페이스입니다.

<ListBox>
 <i:Interaction.Behaviors>
    <behaviors:ListBoxSelectedItemsBehavior SelectedItems="{Binding SelectedItems, Mode=OneWayToSource}" />
 </i:Interaction.Behaviors>

ListBoxDataContextViewModelSelectedItems 속성이 있다고 가정하면 SelectedItems 가 자동으로 업데이트됩니다. View 에서 구독하는 event 캡슐화했습니다. 즉,

<ListBox SelectionChanged="ListBox_SelectionChanged"/>

원하는 경우 Behavior 클래스를 DataGrid 유형으로 변경할 수 있습니다.


모델에 "IsSelected"속성을 추가하고 행에 checkBox를 추가 할 수 있습니다.


재사용 가능한 일반 기본 클래스를 사용할 수 있습니다. 이렇게하면 코드와 UI 모두에서 행을 선택할 수 있습니다.

이것은 내가 선택할 수있는 예제 클래스 다.

public class MyClass
{
    public string MyString {get; set;}   
}

선택 가능한 클래스에 대한 일반 기본 클래스를 만듭니다. INotifyPropertyChanged는 IsSelected를 설정할 때 UI를 업데이트합니다.

public class SelectableItem<T> : System.ComponentModel.INotifyPropertyChanged
{
    public SelectableItem(T item)
    {
        Item = item;
    }

    public T Item { get; set; }

    bool _isSelected;

    public bool IsSelected {
        get {
            return _isSelected;
        }
        set {
            if (value == _isSelected)
            {
                return;
            }

            _isSelected = value;

            if (PropertyChanged != null)
            { 
                PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs("IsSelected"));
            }
        }
    }

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
}

선택 가능한 클래스 만들기

public class MySelectableItem: SelectableItem<MyClass>
{
    public MySelectableItem(MyClass item)
       :base(item)
    {
    }
}

바인딩 할 속성 만들기

ObservableCollection<MySelectableItem> MyObservableCollection ...

유행을 설정하십시오

MyObservableCollection = myItems.Select(x => new MySelectableItem(x));

DataGrid에 바인딩하고 MySelectedItem의 IsSelected 속성에 바인딩하는 DataGridRow에 스타일을 추가합니다.

<DataGrid  
    ItemsSource="{Binding MyObservableCollection}"
    SelectionMode="Extended">
    <DataGrid.Resources>
        <Style TargetType="DataGridRow">
            <Setter Property="IsSelected" Value="{Binding IsSelected}" />
        </Style>
    </DataGrid.Resources>
</DataGrid>

선택한 행 / 항목을 가져 오려면

var selectedItems = MyObservableCollection.Where(x=>x.IsSelected).Select(y=>y.Item);

행 / 항목을 선택하려면

MyObservableCollection[0].IsSelected = true;

편집 ---> EnableRowVirtualization이 true 일 때 작동하지 않는 것처럼 보입니다.


내 애플 리케이션 에이 솔루션을 사용합니다 :

XAML :

<i:Interaction.Triggers>
     <i:EventTrigger EventName="SelectionChanged">
         <i:InvokeCommandAction Command="{Binding SelectItemsCommand}" CommandParameter="{Binding Path=SelectedItems,ElementName=TestListView}"/>
     </i:EventTrigger>
</i:Interaction.Triggers>

xaml 파일의 맨 위에 다음 코드 줄을 추가하십시오.

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

SelectedItemsCommand는 viewmodel에 기록 된 ICommand 유형입니다.

사용 된 DLL :

System.Windows.Interactivity.dll


첨부 된 속성을 만들 수 있습니다.

이렇게하면 바인딩 한 모든 목록에 대해 IsSelected 속성을 저장하지 않습니다. 나는 ListBoxListBox 작업을 수행했지만 목록보기에서 사용하기 위해 수정할 수 있습니다.

<ListBox SelectionMode="Multiple"
         local:ListBoxMultipleSelection.SelectedItems="{Binding SelectedItems}" >

추가 정보 : WPF - 바인딩 ListBox SelectedItems - 연결된 속성 VS 스타일 .







c# wpf xaml mvvm datagrid