programing

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

goodsources 2023. 4. 11. 21:58
반응형

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

여러 항목을 선택하려면 어떻게 해야 합니까?DataGridMVVM WPF 프로젝트에서요?

를 위해 사용자 지정 종속성 속성을 추가할 수 있습니다.

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
}

이제 이것을 사용할 수 있습니다.dataGridXAML:

<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 디자인이 도움이 되었으면 좋겠습니다.

내가 하고 싶은 것은,Behaviors사용.System.Windows.Interactivity프로젝트에서 수동으로 참조해야 합니다.

노출되지 않는 제어장치가 주어지면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내가 할 수 있는 건Binding어디선가 이렇게ixmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"그리고.behaviors의 네임스페이스입니다.Behavior학급

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

이 경우,DataContext를 위해ListBox가지고 있다SelectedItems의 재산ViewModel그러면 자동으로 업데이트 됩니다.SelectedItems. 를 캡슐화했습니다.event에서 서브스크라이브View예.,

<ListBox SelectionChanged="ListBox_SelectionChanged"/>

를 변경할 수 있습니다.Behavior종류별 클래스DataGrid네가 원한다면.

앱에서 다음 솔루션을 사용합니다.

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"

선택된ItemsCommand는 뷰 모델에 기록되는 ICommand 유형입니다.

사용된 DLL:

System.Windows.Interactivity.dll

디폴트 설정DataGridWPF에서는 바인딩을 사용할 수 없습니다.SelectedItem- Property, 원인:SelectedItemsProperty가 DependencyProperty가 아닙니다.

원하는 것을 얻기 위한 한 가지 방법은SelectionChanged- 선택한 항목을 저장하는 ViewModel 속성을 업데이트하는 DataGrid 이벤트.

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

C#

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>

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

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

이것은 나의 예제 클래스입니다. 선택 가능하기를 원합니다.

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

선택 가능한 클래스의 일반 기본 클래스를 만듭니다.이노티파이PropertyChanged는 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));

데이터 그리드에 바인딩하고 MySelected의 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;

[Edit] : : > [ Enable Row Virtualization ]가 true이면 동작하지 않는 것 같습니다.

WPF 데이터 그리드, WPF 데이터 그리드Data Grid data data data 。Rows.SelectionMode § DataGrid.Rows. §을 각각" 및 "합니다."확장" "CellOrowHeader" "CellOrowHeader" 입니다.블렌드사용자는 Shift 키 또는 Ctrl 키를 사용하여 원하는 만큼 각 셀, 전체 행 등을 선택할 수 있습니다. 여기에 이미지 설명 입력

현재 진행 중인 프로젝트는 MVVM Light를 사용하고 있으며, 이 블로그 게시물이 가장 간단한 해결책이라는 을 알게 되었습니다.여기서 해결책을 다시 설명하겠습니다.

모델 표시:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
...

public class SomeVm : ViewModelBase {

    public SomeVm() {
        SelectItemsCommand = new RelayCommand<IList>((items) => {
            Selected.Clear();
            foreach (var item in items) Selected.Add((SomeClass)item);
        });

        ViewCommand = new RelayCommand(() => {
            foreach (var selected in Selected) {
                // todo do something with selected items
            }
        });
    }

    public List<SomeClass> Selected { get; set; }
    public RelayCommand<IList> SelectionChangedCommand { get; set; }
    public RelayCommand ViewCommand { get; set; }
}

XAML:

<Window
    ...
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:command="http://www.galasoft.ch/mvvmlight"
    ...
    <DataGrid
        Name="SomeGrid"
        ...
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="SelectionChanged">
                <command:EventToCommand
                    Command="{Binding SelectionChangedCommand}"
                    CommandParameter="{Binding SelectedItems, ElementName=SomeGrid}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
        ...
        <DataGrid.ContextMenu>
            <ContextMenu>
                <MenuItem Header="View" Command="{Binding ViewCommand}" />
            </ContextMenu>
        </DataGrid.ContextMenu>
        ...

제 솔루션은 Sandesh와 거의 비슷합니다.한편, 저는 이 문제를 해결하기 위해 Custom Data Grid를 사용하지 않았습니다.대신 뷰 모델에서 적절한 기능을 가진 플러스 버튼 클릭 이벤트를 사용했습니다.제 코드에서 중요한 점은 데이터그리드 위치에서 여러 사용자 개체를 삭제할 수 있는 것이 PeopleList 속성(ObservableCollection)에 바인딩되어 있다는 것입니다.

이것은 나의 모델입니다.

 public class Person
    {
        public Person()
        {

        }

        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Age { get; set; }

    }
}

이것은 내 View Model입니다(필요한 부품만 해당).

public class PersonViewModel : BindableBase
    {
        private ObservableCollection<Person> _peopleList;
        // to be able to delete or save more than one person object
        private List<Person> _selectedPersonList;

        //MyICommand
        public MyICommand AddCommand { get; set; }
        public MyICommand DeleteCommand { get; set; }

        private string _firstName;
        private string _lastName;
        private int _age;

        public PersonViewModel()
        {
            _peopleList = new ObservableCollection<Person>();
            LoadPerson();
            AddCommand = new MyICommand(AddPerson);
            DeleteCommand = new MyICommand(DeletePerson, CanDeletePerson);
            // To be able to delete or save more than one person
            _selectedPersonList = new List<Person>();
        } 
public ObservableCollection<Person> PeopleList
        {
            get { return _peopleList; }
            set
            {
                _peopleList = value;
                RaisePropertyChanged("PeopleList");
            }
        }
 public List<Person> SelectedPersonList
        {
            get { return _selectedPersonList; }
            set
            {
                if (_selectedPersonList != value)
                {
                    RaisePropertyChanged("SelectedPersonList");
                }
            }
        }
 private void DeletePerson()
        {
            // to be able to delete more than one person object
            foreach (Person person in SelectedPersonList)
            {
                PeopleList.Remove(person);
            }
            MessageBox.Show(""+SelectedPersonList.Count); // it is only a checking
            SelectedPersonList.Clear(); // it is a temp list, so it has to be cleared after the button push
        }
 public void GetSelectedPerson(DataGrid datagrid)
        {

            IList selectedItems = datagrid.SelectedItems;
            foreach (Person item in selectedItems)
            {
                SelectedPersonList.Add(item);
            }
        }

마이뷰(xmal):

<UserControl x:Class="DataBase.Views.PersonView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:DataBase.Views"
             xmlns:viewModel="clr-namespace:DataBase.ViewModels" d:DataContext="{d:DesignInstance Type=viewModel:PersonViewModel}"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <StackPanel Orientation="Vertical" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2" Background="AliceBlue">
            <TextBlock Text="First Name:"/>
            <TextBox x:Name="firstNameTxtBox" Text="{Binding FirstName, UpdateSourceTrigger=PropertyChanged}"/>
            <TextBlock Text="Last Name:"/>
            <TextBox x:Name="lastNameTxtBox" Text="{Binding LastName, UpdateSourceTrigger=PropertyChanged}"/>
            <TextBlock Text="Age:"/>
            <TextBox x:Name="ageTxtBox" Text="{Binding Age}"/>
            <TextBlock Text="{Binding FullName}"/>
            <Button Content="Add" IsEnabled="{Binding CanAddPerson}" Command="{Binding AddCommand}"/>
            <Button Content="Delete" Command="{Binding DeleteCommand}" Click="Delete_Click"/>
            <DataGrid x:Name="datagridPeopleList" ItemsSource="{Binding PeopleList}" AutoGenerateColumns="True" SelectedItem="{Binding SelectedPerson}" SelectionMode="Extended" SelectionUnit="FullRow"/>
            <!--<ListView Height="50" ItemsSource="{Binding PeopleList}" SelectedItem="{Binding SelectedPerson}" Margin="10">
            </ListView>-->
        </StackPanel>
    </Grid>
</UserControl>

마이뷰(.cs):

 public partial class PersonView : UserControl
    {
        public PersonViewModel pvm;
        public PersonView()
        {
            pvm = new PersonViewModel();
            InitializeComponent();
            DataContext = pvm;
        }

        private void Delete_Click(object sender, RoutedEventArgs e)
        {
            pvm.GetSelectedPerson(datagridPeopleList);
        }
    }

세계 최악의 (고상하지 않은) 솔루션이 아니라 유용하기를 바랍니다:D

언급URL : https://stackoverflow.com/questions/22868445/select-multiple-items-from-a-datagrid-in-an-mvvm-wpf-project

반응형