如何获取XAML中定义的CollectionView

时间:2021-07-25 06:32:54

I wanted to bind to an ObservableCollection in XAML and also apply the grouping there. In principle, this worked fine.

我想绑定到XAML中的ObservableCollection并在那里应用分组。原则上,这很好。

<UserControl.Resources>
    <CollectionViewSource x:Key="cvs" Source="{Binding Path=TestTemplates}">
        <CollectionViewSource.SortDescriptions>
            <scm:SortDescription PropertyName="Title"/>
        </CollectionViewSource.SortDescriptions>
        <CollectionViewSource.GroupDescriptions>
            <PropertyGroupDescription PropertyName="TestCategory"/>
        </CollectionViewSource.GroupDescriptions>
    </CollectionViewSource>
</UserControl.Resources>

Then the data binding expression became ItemsSource="{Binding Source={StaticResource ResourceKey=cvs}}" instead of ItemsSource="{Binding Path=TestTemplates}".

然后数据绑定表达式变为ItemsSource =“{Binding Source = {StaticResource ResourceKey = cvs}}”而不是ItemsSource =“{Binding Path = TestTemplates}”。

At first, everything seemed cool, until I wanted to refresh the UI from the view model. The problem is, that CollectionViewSource.GetDefaultView(TestTemplates) returned a different view than the one from XAML where the grouping was applied. Thus, I could not set selection or do anything useful with it.

起初,一切看起来都很酷,直到我想从视图模型中刷新UI。问题是,CollectionViewSource.GetDefaultView(TestTemplates)返回的视图与应用分组的XAML中的视图不同。因此,我无法设置选择或做任何有用的事情。

I could fix it by binding the list again directly to the view model's property and setting up the grouping in the code-behind. But I'm not that happy with this solution.

我可以通过将列表再次直接绑定到视图模型的属性并在代码隐藏中设置分组来修复它。但我对这个解决方案并不满意。

private void UserControlLoaded(object sender, RoutedEventArgs e)
{
    IEnumerable source = TemplateList.ItemsSource;
    var cvs = (CollectionView)CollectionViewSource.GetDefaultView(source);
    if (cvs != null)
    {
        cvs.SortDescriptions.Add(new SortDescription("Title", ListSortDirection.Ascending));
        cvs.GroupDescriptions.Add(new PropertyGroupDescription("TestCategory"));
    }
}

I assume, the reason for that is already given by John Skeet here.

我想,这个原因已经由John Skeet在这里给出了。

Nevertheless, I would expect that there should be a way to get the right view. Am I wrong?

尽管如此,我希望应该有一种方法来获得正确的观点。我错了吗?

3 个解决方案

#1


5  

I tend to just expose the collection view from the VM rather than have the view define it:

我倾向于只从VM公开集合视图而不是让视图定义它:

public ICollection<Employee> Employees
{
    get { ... }
}

public ICollectionView EmployeesView
{
    get { ... }
}

That way your VM has full control over what is exposed to the view. It can, for example, change the sort order in response to some user action.

这样,您的VM就可以完全控制对视图的显示内容。例如,它可以更改排序顺序以响应某些用户操作。

#2


5  

You could not just do that?

你不能这样做吗?

var _viewSource = this.FindResource("cvs") as CollectionViewSource;

If the data is connected, I assume that will have an updated view.

如果数据已连接,我认为将有更新的视图。

#3


1  

Found a way, based on J. Lennon's answer. If I pass something that has access to the resources with my command, then I can look up the CollectionViewSource there.

找到了一种方法,基于J. Lennon的回答。如果我使用my命令传递了可以访问资源的内容,那么我可以在那里查找CollectionViewSource。

In XAML (CollectionViewResource as above):

在XAML中(如上所述的CollectionViewResource):

<Button Command="{Binding Command}" CommandParameter="{Binding RelativeSource={RelativeSource Self}}">Do it!</Button>

And in the VM code:

在VM代码中:

private void Execute(object parm)
{
    var fe = (FrameworkElement)parm;
    var cvs = (CollectionViewSource)fe.FindResource("cvs");
    cvs.View.Refresh();
}

The Execute is the one that is given to the RelayCommand.

Execute是给RelayCommand的那个。

This would answer the question, but I don't like it very much. Opinions?

这会回答这个问题,但我不太喜欢它。意见?

#1


5  

I tend to just expose the collection view from the VM rather than have the view define it:

我倾向于只从VM公开集合视图而不是让视图定义它:

public ICollection<Employee> Employees
{
    get { ... }
}

public ICollectionView EmployeesView
{
    get { ... }
}

That way your VM has full control over what is exposed to the view. It can, for example, change the sort order in response to some user action.

这样,您的VM就可以完全控制对视图的显示内容。例如,它可以更改排序顺序以响应某些用户操作。

#2


5  

You could not just do that?

你不能这样做吗?

var _viewSource = this.FindResource("cvs") as CollectionViewSource;

If the data is connected, I assume that will have an updated view.

如果数据已连接,我认为将有更新的视图。

#3


1  

Found a way, based on J. Lennon's answer. If I pass something that has access to the resources with my command, then I can look up the CollectionViewSource there.

找到了一种方法,基于J. Lennon的回答。如果我使用my命令传递了可以访问资源的内容,那么我可以在那里查找CollectionViewSource。

In XAML (CollectionViewResource as above):

在XAML中(如上所述的CollectionViewResource):

<Button Command="{Binding Command}" CommandParameter="{Binding RelativeSource={RelativeSource Self}}">Do it!</Button>

And in the VM code:

在VM代码中:

private void Execute(object parm)
{
    var fe = (FrameworkElement)parm;
    var cvs = (CollectionViewSource)fe.FindResource("cvs");
    cvs.View.Refresh();
}

The Execute is the one that is given to the RelayCommand.

Execute是给RelayCommand的那个。

This would answer the question, but I don't like it very much. Opinions?

这会回答这个问题,但我不太喜欢它。意见?