- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这就是我想要的:如果我将 ICollectionview 绑定(bind)到 DataGrid,我不想在我的 Viewmodel 中丢失 SortDescription。
我创建了一个小示例项目来了解我的意思。在我的项目中,我只是使用 Usercontrol 在 DataGrid 中显示我的数据。如果我这样做,当用户控件卸载时,SortDescritpion 消失,因为 ItemsSource 设置为 null。如果我使用 TemplateSelector 来显示我的 UserControl,SortDescription 不会消失 并且 ItemsSource 在卸载时不会设置为 null。问题是,为什么会有这些不同的行为?这 2 种行为中的一种是错误吗?
顺便说一句。我使用 .Net 4.5.1 但安装了 4.6.1 和 system.Windows.Interactivity 4.0.0.0
主窗口.xaml
<Window x:Class="DataGridICollectionView.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DataGridICollectionView"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type local:ViewmodelListe}">
<local:MyViewUc/>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ToolBar Grid.Row="0">
<Button Content="SetWorkspace MyView" Click="Button_Click"/>
<Button Content="SetWorkspace Other" Click="Button_Click_1"/>
</ToolBar>
<ContentPresenter Grid.Row="1" Content="{Binding Workspace}"/>
</Grid>
</Window>
主窗口.xaml.cs
namespace DataGridICollectionView
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
private object _workspace;
public MainWindow()
{
InitializeComponent();
MyViewVm = new ViewmodelListe();
DataContext = this;
}
public ViewmodelListe MyViewVm { get; set; }
public object Workspace
{
get { return _workspace; }
set
{
_workspace = value;
OnPropertyChanged();
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Workspace = MyViewVm;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Workspace = "Other";
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ViewmodelListe : INotifyPropertyChanged
{
public ViewmodelListe()
{
Persons = new ObservableCollection<Person>();
MyView = CollectionViewSource.GetDefaultView(Persons);
Persons.Add(new Person() {FirstName = "P1", LastName = "L1"});
Persons.Add(new Person() {FirstName = "P2", LastName = "L2"});
Persons.Add(new Person() {FirstName = "P3", LastName = "L3"});
}
public ObservableCollection<Person> Persons { get; private set; }
public ICollectionView MyView { get; private set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Person : INotifyPropertyChanged
{
private string _firstName;
private string _lastName;
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
OnPropertyChanged();
}
}
public string LastName
{
get { return _lastName; }
set
{
_lastName = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class TestBehavior : Behavior<DataGrid>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Unloaded += AssociatedObjectUnloaded;
}
private void AssociatedObjectUnloaded(object sender, RoutedEventArgs e)
{
//look at this in Debug Mode, its NULL if you dont use the TemplateSelector
var itemssource = AssociatedObject.ItemsSource;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.Unloaded -= AssociatedObjectUnloaded;
}
}
}
MyGridControl.xaml
<UserControl x:Class="DataGridICollectionView.MyGridControl"
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:DataGridICollectionView"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<DataGrid ItemsSource="{Binding MyView}" AutoGenerateColumns="True">
<i:Interaction.Behaviors>
<local:TestBehavior/>
</i:Interaction.Behaviors>
</DataGrid>
</Grid>
</UserControl>
MyViewUc.xaml
<UserControl x:Class="DataGridICollectionView.MyViewUc"
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:DataGridICollectionView"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<DataTemplate x:Key="MyViewCrap">
<local:MyGridControl/>
</DataTemplate>
<local:MyTemplateSelector x:Key="Selector" GridView="{StaticResource MyViewCrap}" />
</UserControl.Resources>
<Grid>
<!--When using Contentcontrol with TemplateSelector- ItemsSource is NOT set to null -->
<ContentControl Content="{Binding .}" ContentTemplateSelector="{StaticResource Selector}"/>
<!--When using MyGridControl withOUT TemplateSelector- ItemsSource is set to NULL -->
<!--<local:MyGridControl/>-->
</Grid>
</UserControl>
MyViewUc.xaml.cs
namespace DataGridICollectionView
{
/// <summary>
/// Interaktionslogik für MyViewUc.xaml
/// </summary>
public partial class MyViewUc : UserControl
{
public MyViewUc()
{
InitializeComponent();
}
}
public class MyTemplateSelector : DataTemplateSelector
{
public DataTemplate GridView { get; set; }
public override DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
{
var chooser = item as ViewmodelListe;
if (chooser == null)
{
return base.SelectTemplate(item, container);
}
return GridView;
}
}
}
编辑:我最终使用了这个
public class MyDataGrid : DataGrid
{
static MyDataGrid ()
{
ItemsSourceProperty.OverrideMetadata(typeof(MyDataGrid ),new FrameworkPropertyMetadata(null, OnPropertyChangedCallBack, OnCoerceItemsSourceProperty));
}
private ICollectionView _defaultView;
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
{
if(_defaultView != null)
_defaultView.CollectionChanged -= LiveSortingPropertiesOnCollectionChanged;
base.OnItemsSourceChanged(oldValue, newValue);
_defaultView = newValue as ICollectionView;
if(_defaultView != null)
_defaultView.CollectionChanged += LiveSortingPropertiesOnCollectionChanged;
}
private void LiveSortingPropertiesOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Reset)
{
foreach (var dataGridColumn in this.Columns)
{
var isSortDirectionSetFromCollectionView = false;
foreach (var sortDescription in _defaultView.SortDescriptions)
{
if (dataGridColumn.SortMemberPath == sortDescription.PropertyName)
{
dataGridColumn.SortDirection = sortDescription.Direction;
isSortDirectionSetFromCollectionView = true;
break;
}
}
if (!isSortDirectionSetFromCollectionView)
{
dataGridColumn.SortDirection = null;
}
}
}
}
private static void OnPropertyChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var grd = d as MyDataGrid ;
var view = e.NewValue as ICollectionView;
if (grd == null || view == null)
return;
foreach (var dataGridColumn in grd.Columns)
{
var isSortDirectionSetFromCollectionView = false;
foreach (var sortDescription in view.SortDescriptions)
{
if (dataGridColumn.SortMemberPath == sortDescription.PropertyName)
{
dataGridColumn.SortDirection = sortDescription.Direction;
isSortDirectionSetFromCollectionView = true;
break;
}
}
//wenn die View nicht sortiert war, auch die column nicht Sortieren
if (!isSortDirectionSetFromCollectionView)
{
dataGridColumn.SortDirection = null;
}
}
}
private static object OnCoerceItemsSourceProperty(DependencyObject d, object baseValue)
{
// do nothing here - we just want to override parent behaviour.
// The _only_ thing DataGrid does here is clearing sort descriptors
return baseValue;
}
}
最佳答案
当您直接在 MyViewUc 中托管 MyGridControl 时(案例 1)- 当您切换工作区并且卸载 MyViewUC 时,它的数据上下文设置为空。因为 MyGridControl 是直接子级 - 它的 datacontext 也设置为 null,而 DataGrid 的 DataContext 又设置为 null。这也将 ItemsSource 设置为 null,因为它绑定(bind)到 DataContext。您可以通过查看行为中 DataGrid 的 DataContext 来验证这一点。这种行为在我看来是完全合理的。
当您使用模板选择器时:MyViewUC 被卸载,它的数据上下文被设置为空。然后 ContentControl Content 也设置为 null。现在的问题是:当您使用 ContentTemplateSelector 时,旧的(未加载的)MyGridControl 的 DataContext 未设置为 null。您可以在您的行为中验证这一点,这就是保留 ItemsSource 和排序描述符的原因。
现在,我认为第二个行为是不正确的,对于这个由 ContentTemplateSelector 创建的未加载控件,应该将 datacontext 设置为 null。这背后的逻辑不是很简单 - 您可以自己查看 ContentPresenter.OnContentChanged 方法的源代码,您将在其中看到内容更改时 DataContext 何时未更新。
更新:我看到您主要关心的是丢失排序描述符,但这是丢失 DataContext 并将 ItemsSource 设置为 null 的直接后果。对我来说,这种行为看起来很合理,但我确实看到很多人并非如此,因此甚至有关于此问题的错误报告:https://connect.microsoft.com/VisualStudio/feedback/details/592897/collectionviewsource-sorting-only-the-first-time-it-is-bound-to-a-source
您可以在 DataGrid 源代码中看到自己:
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
{
base.OnItemsSourceChanged(oldValue, newValue);
if (newValue == null)
this.ClearSortDescriptionsOnItemsSourceChange();
// more code here....
}
因此,当您将 ItemsSource 设置为 null 时 - 所有排序描述符都会被明确清除。在上面的链接中,您可以找到一些您可能会觉得有用的解决方法。
更新 2:您可以考虑尝试通过继承 DataGrid 来修复该行为。我并不是说这是完美的解决方案,但使用 ContentTemplateSelector 也不是。当 ItemsSource 设置为 null 时,有两个地方会清除排序描述符 - 在 OnItemsSourceChanged 和 OnCoerceItemsSourceProperty 中。因此,您可以执行以下操作:
public class MyDataGrid : DataGrid {
static MyDataGrid() {
ItemsSourceProperty.OverrideMetadata(typeof(MyDataGrid), new FrameworkPropertyMetadata(null, OnCoerceItemsSourceProperty));
}
private static object OnCoerceItemsSourceProperty(DependencyObject d, object baseValue) {
// do nothing here - we just want to override parent behaviour.
// The _only_ thing DataGrid does here is clearing sort descriptors
return baseValue;
}
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue) {
SortDescription[] sorts = null;
if (newValue == null) {
// preserve sort descriptors when setting ItemsSource to null
sorts = Items.SortDescriptions.ToArray();
}
// they will now be cleared here
base.OnItemsSourceChanged(oldValue, newValue);
if (sorts != null) {
// restore them back
foreach (var sort in sorts) {
Items.SortDescriptions.Add(sort);
}
}
}
}
通过上面的代码,您将看到在切换数据上下文之间,排序描述符保留在您的 MyView 中。
关于c# - 带有 ICollectionView SortDescription 的数据网格丢失了 - 错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36197717/
初学者 android 问题。好的,我已经成功写入文件。例如。 //获取文件名 String filename = getResources().getString(R.string.filename
我已经将相同的图像保存到/data/data/mypackage/img/中,现在我想显示这个全屏,我曾尝试使用 ACTION_VIEW 来显示 android 标准程序,但它不是从/data/dat
我正在使用Xcode 9,Swift 4。 我正在尝试使用以下代码从URL在ImageView中显示图像: func getImageFromUrl(sourceUrl: String) -> UII
我的 Ubuntu 安装 genymotion 有问题。主要是我无法调试我的数据库,因为通过 eclipse 中的 DBMS 和 shell 中的 adb 我无法查看/data/文件夹的内容。没有显示
我正在尝试用 PHP 发布一些 JSON 数据。但是出了点问题。 这是我的 html -- {% for x in sets %}
我观察到两种方法的结果不同。为什么是这样?我知道 lm 上发生了什么,但无法弄清楚 tslm 上发生了什么。 > library(forecast) > set.seed(2) > tts lm(t
我不确定为什么会这样!我有一个由 spring data elasticsearch 和 spring data jpa 使用的类,但是当我尝试运行我的应用程序时出现错误。 Error creatin
在 this vega 图表,如果我下载并转换 flare-dependencies.json使用以下 jq 到 csv命令, jq -r '(map(keys) | add | unique) as
我正在提交一个项目,我必须在其中创建一个带有表的 mysql 数据库。一切都在我这边进行,所以我只想检查如何将我所有的压缩文件发送给使用不同计算机的人。基本上,我如何为另一台计算机创建我的数据库文件,
我有一个应用程序可以将文本文件写入内部存储。我想仔细看看我的电脑。 我运行了 Toast.makeText 来显示路径,它说:/数据/数据/我的包 但是当我转到 Android Studio 的 An
我喜欢使用 Genymotion 模拟器以如此出色的速度加载 Android。它有非常好的速度,但仍然有一些不稳定的性能。 如何从 Eclipse 中的文件资源管理器访问 Genymotion 模拟器
我需要更改 Silverlight 中文本框的格式。数据通过 MVVM 绑定(bind)。 例如,有一个 int 属性,我将 1 添加到 setter 中的值并调用 OnPropertyChanged
我想向 Youtube Data API 提出请求,但我不需要访问任何用户信息。我只想浏览公共(public)视频并根据搜索词显示视频。 我可以在未经授权的情况下这样做吗? 最佳答案 YouTube
我已经设置了一个 Twilio 应用程序,我想向人们发送更新,但我不想回复单个文本。我只是想让他们在有问题时打电话。我一切正常,但我想在发送文本时显示传入文本,以确保我不会错过任何问题。我正在使用 p
我有一个带有表单的网站(目前它是纯 HTML,但我们正在切换到 JQuery)。流程是这样的: 接受用户的输入 --- 5 个整数 通过 REST 调用网络服务 在服务器端运行一些计算...并生成一个
假设我们有一个名为 configuration.js 的文件,当我们查看内部时,我们会看到: 'use strict'; var profile = { "project": "%Projec
这部分是对 Previous Question 的扩展我的: 我现在可以从我的 CI Controller 成功返回 JSON 数据,它返回: {"results":[{"id":"1","Sourc
有什么有效的方法可以删除 ios 中 CBL 的所有文档存储?我对此有疑问,或者,如果有人知道如何从本质上使该应用程序像刚刚安装一样,那也会非常有帮助。我们正在努力确保我们的注销实际上将应用程序设置为
我有一个 Rails 应用程序,它与其他 Rails 应用程序通信以进行数据插入。我使用 jQuery $.post 方法进行数据插入。对于插入,我的其他 Rails 应用程序显示 200 OK。但在
我正在为服务于发布请求的 API 调用运行单元测试。我正在传递请求正文,并且必须将响应作为帐户数据返回。但我只收到断言错误 注意:数据是从 Azure 中获取的 spec.js const accou
我是一名优秀的程序员,十分优秀!