programing

컬렉션 보기를 올바르게 사용하는 방법뷰 모델의 소스

sourcejob 2023. 4. 29. 09:14
반응형

컬렉션 보기를 올바르게 사용하는 방법뷰 모델의 소스

드래그 앤 드롭을 사용하여 데이터 소스 개체(DB 모델)를DataGrid(기본적으로 WPF를 사용한 엔티티 프레임워크 데이터 바인딩의 이 예를 따릅니다.

이 구현에서는 모든 것이 정상적으로 작동합니다.

XAML

<Window.Resources>    
<CollectionViewSource x:Key="categoryViewSource"  
    d:DesignSource="{d:DesignInstance {x:Type local:Category}, CreateList=True}"/>
</Window.Resources>
<Grid DataContext="{StaticResource categoryViewSource}">
..

코드비하

private void Window_Loaded(object sender, RoutedEventArgs e)
{
   System.Windows.Data.CollectionViewSource categoryViewSource =
      ((System.Windows.Data.CollectionViewSource)(this.FindResource("categoryViewSource")));

  _context.Categories.Load();
  categoryViewSource.Source = _context.Categories.Local;        
}

모델 보기

public MainWindow()
{
    InitializeComponent();
    this.DataContext = new MyViewModel();
}

그러나 ViewModel 내에서 동일한 코드를 사용하려고 하면 작동하지 않습니다(FindResource사용할 수 없음), 게다가, 저는 이것이 올바른 접근법이라고 생각하지 않습니다(즉, 사용하는 것).x:Key(MVVM에 있음).

올바른 구현 방법이 무엇인지 알려주시면 감사하겠습니다.CollectionViewSource그리고.DataBinding와 함께DataGrid.

사용할 수 있는 두 가지 옵션이 있습니다.CollectionViewSourceMVVM과 함께 올바르게 -

  1. 노출ObservableCollection항목의(Categories당신의 경우)를 통해ViewModel생성CollectionViewSource이런 식으로 XAML에서 -

    <CollectionViewSource Source="{Binding Path=Categories}">
        <CollectionViewSource.SortDescriptions>
           <scm:SortDescription PropertyName="CategoryName" />
        </CollectionViewSource.SortDescriptions>
    </CollectionViewSource>
    

    scm:xmlns:scm="clr-namespace:System.ComponentModel;assembly=Wind‌​owsBase"

    참고 항목 - CollectionView를 사용하여 XAML에서 수집출처

  2. 생성 및 노출ICollectionView당신으로부터 직접ViewModel

    WPF에서 데이터 탐색, 그룹화, 정렬필터링 방법을 참조하십시오.

다음 예제는 컬렉션 보기를 만들고 이를 다음으로 바인딩하는 방법을 보여줍니다.ListBox

XAML 보기:

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
    x:Class="CustomerView">
    <ListBox ItemsSource={Binding Customers} />
</Window>

코드 뒤 보기:

public class CustomerView : Window
{
   public CustomerView()
   {
       DataContext = new CustomerViewModel();
   }
}

모델 보기:

public class CustomerViewModel
{
    private readonly ICollectionView customerView;

    public ICollectionView Customers
    {
        get { return customerView; }
    }

    public CustomerViewModel()
    {
        IList<Customer> customers = GetCustomers();
        customerView = CollectionViewSource.GetDefaultView( customers );
    }
}

업데이트:

Q. 정렬할 속성이 없는 경우(예: 속성이 있는 경우)ObservableCollection끈이나 인트의?

A. 이 경우 속성 이름으로 .을 사용할 수 있습니다.

<scm:SortDescription PropertyName="." />

나는 그것이 가지고 있는 것이 편리하다는 것을 발견했습니다.CollectionViewSource내 View 모델에서 그리고 바인딩.ListBox(나의 경우) 에CollectionViewSource.View설정하는 동안CollectionViewSource.Source내가 사용하고 싶은 목록이 될 것입니다.

이와 같은 경우:

모델 보기:

    public DesignTimeVM()  //I'm using this as a Design Time VM 
    {
        Items = new List<Foo>();
        Items.Add(new Foo() { FooProp= "1", FooPrep= 20.0 });
        Items.Add(new Foo() { FooProp= "2", FooPrep= 30.0 });

        FooViewSource = new CollectionViewSource();
        FooViewSource.Source = Items;

        SelectedFoo = Items.First();

        //More code as needed
    }

XAML:

<ListBox ItemsSource="{Binding FooViewSource.View}" SelectedItem="{Binding SelectedFoo}"/>

, 필요에 따라 VM에서 다음과 같은 작업을 수행할 수 있습니다(https://blogs.msdn.microsoft.com/matt/2008/08/28/collectionview-deferrefresh-my-new-best-friend/ 참조).

        using (FooViewSource.DeferRefresh())
        {
            //Remove an old Item
            //add New Item
            //sort list anew, etc. 
        }

저는 이것이 사용할 때 가능하다고 생각합니다.ICollectionView객체도 있지만, 블로그 링크의 데모 코드는 목록 상자를 직접 참조하는 무언가 뒤에 있는 코드인 것 같습니다. 제가 피하려고 합니다.

질문하기 전에 먼저 설계 시간 VM: WPF 설계 시간 보기 모델을 사용하는 방법을 설명합니다.

참고로, 또 다른 방법은 첨부된 속성을 사용하는 것입니다.CollectionViewSource그런 다음 기능을 연결합니다.ViewModel(인터페이스 구현).

이 데모는 필터링을 위한 매우 기본적인 데모이며, VM에 대한 두 번째 수집과 같은 작업이 필요하지만 일반적인 기술을 보여주기에는 충분하다고 생각합니다.

만약 이것이 다른 방법들보다 더 좋거나 더 나쁘다면, 저는 단지 이것을 하는 다른 방법이 있다는 것을 지적하고 싶습니다.

연결된 속성의 정의:

public static class CollectionViewSourceFilter
{
    public static IFilterCollectionViewSource GetFilterObject(CollectionViewSource obj)
    {
        return (IFilterCollectionViewSource)obj.GetValue(FilterObjectProperty);
    }

    public static void SetFilterObject(CollectionViewSource obj, IFilterCollectionViewSource value)
    {
        obj.SetValue(FilterObjectProperty, value);
    }

    public static void FilterObjectChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        if (e.OldValue is IFilterCollectionViewSource oldFilterObject
            && sender is CollectionViewSource oldCvs)
        {
            oldCvs.Filter -= oldFilterObject.Filter;
            oldFilterObject.FilterRefresh -= (s, e2) => oldCvs.View.Refresh();
        }

        if (e.NewValue is IFilterCollectionViewSource filterObject
            && sender is CollectionViewSource cvs)
        {
            cvs.Filter += filterObject.Filter;
            filterObject.FilterRefresh += (s,e2) => cvs.View.Refresh();
        }
    }

    public static readonly DependencyProperty FilterObjectProperty = DependencyProperty.RegisterAttached(
        "FilterObject",
        typeof(Interfaces.IFilterCollectionViewSource),
        typeof(CollectionViewSourceFilter),
        new PropertyMetadata(null,FilterObjectChanged)
    );
}

인터페이스:

public interface IFilterCollectionViewSource
{
    void Filter(object sender, FilterEventArgs e);
    event EventHandler FilterRefresh;
}

xaml에서의 사용:

<CollectionViewSource
        x:Key="yourKey"
        Source="{Binding YourCollection}"
        classes:CollectionViewSourceFilter.FilterObject="{Binding}" />

및 View 모델의 용도:

class YourViewModel : IFilterCollectionViewSource
{
    public event EventHandler FilterRefresh;

    private string _SearchTerm = string.Empty;
    public string SearchTerm
    {
        get { return _SearchTerm; }
        set {
            SetProperty(ref _SearchTerm, value);
            FilterRefresh?.Invoke(this, null);
        }
    }

    private ObservableCollection<YourItemType> _YourCollection = new ObservableCollection<YourItemType>();
    public ObservableCollection<YourItemType> YourCollection
    {
        get { return _YourCollection; }
        set { SetProperty(ref _YourCollection, value); }
    }

    public void Filter(object sender, FilterEventArgs e)
    {
        e.Accepted = (e.Item as YourItemType)?.YourProperty?.ToLower().Contains(SearchTerm.ToLower()) ?? true;
    }
}

언급URL : https://stackoverflow.com/questions/20888619/proper-way-to-use-collectionviewsource-in-viewmodel

반응형