- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
好的,所以这个问题与 Windows Phone 7/Silverlight(更新的 WP7 工具,2010 年 9 月)有关,专门过滤底层 ObservableCollection<T>
.
在使用 WP7 模板 Pivot 控件应用程序时,我遇到了一个问题,即更改 ObservableCollection<T>
中的基础项目。 , 不会导致屏幕上的 ListBox 被更新。基本上,示例应用程序有两个枢轴,第一个直接绑定(bind)到底层 ObservableCollection<T>
,第二个绑定(bind)到 CollectionViewSource
(即,表示对底层 ObservableCollection<T>
的过滤 View )。
正在添加到 ObservableCollection<T>
的基础项目实现INotifyPropertyChanged
,像这样:
public class ItemViewModel : INotifyPropertyChanged
{
public string LineOne
{
get { return _lineOne; }
set
{
if (value != _lineOne)
{
_lineOne = value;
NotifyPropertyChanged("LineOne");
}
}
} private string _lineOne;
public string LineTwo
{
get { return _lineTwo; }
set
{
if (value != _lineTwo)
{
_lineTwo = value;
NotifyPropertyChanged("LineTwo");
}
}
} private string _lineTwo;
public bool IsSelected
{
get { return _isSelected; }
set
{
if (value != _isSelected)
{
_isSelected = value;
NotifyPropertyChanged("IsSelected");
}
}
} private bool _isSelected = false;
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class MainViewModel : INotifyPropertyChanged
{
public MainViewModel()
{
this.Items = new ObservableCollection<ItemViewModel>();
}
public ObservableCollection<ItemViewModel> Items { get; private set; }
public bool IsDataLoaded
{
get;
private set;
}
public void LoadData()
{
this.Items.Add(new ItemViewModel() { LineOne = "runtime one", IsSelected = true, LineTwo = "Maecenas praesent accumsan bibendum" });
this.Items.Add(new ItemViewModel() { LineOne = "runtime two", LineTwo = "Dictumst eleifend facilisi faucibus" });
this.Items.Add(new ItemViewModel() { LineOne = "runtime three", IsSelected = true, LineTwo = "Habitant inceptos interdum lobortis" });
this.Items.Add(new ItemViewModel() { LineOne = "runtime four", LineTwo = "Nascetur pharetra placerat pulvinar" });
this.Items.Add(new ItemViewModel() { LineOne = "runtime five", IsSelected = true, LineTwo = "Maecenas praesent accumsan bibendum" });
this.Items.Add(new ItemViewModel() { LineOne = "runtime six", LineTwo = "Dictumst eleifend facilisi faucibus" });
this.IsDataLoaded = true;
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(String propertyName)
{
if (null != PropertyChanged)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
ItemSource
直接基于
ObservableCollection<T>
列表。在第二个 Pivot 中,屏幕上的 ListBox 有它的
ItemSource
属性设置为
CollectionViewSource
,其基础来源基于
ObservableCollection<T>
已填写
LoadData()
多于。
<phone:PhoneApplicationPage.Resources>
<CollectionViewSource x:Key="IsSelectedCollectionView" Filter="CollectionViewSource_SelectedListFilter">
</CollectionViewSource>
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<!--Pivot Control-->
<controls:Pivot Title="MY APPLICATION">
<!--Pivot item one-->
<controls:PivotItem Header="first">
<!--Double line list with text wrapping-->
<ListBox x:Name="FirstListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432">
<TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</controls:PivotItem>
<!--Pivot item two-->
<controls:PivotItem Header="second">
<!--Triple line list no text wrapping-->
<ListBox x:Name="SecondListBox" Margin="0,0,-12,0" ItemsSource="{Binding Source={StaticResource IsSelectedCollectionView}}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17">
<TextBlock Text="{Binding LineOne}" TextWrapping="NoWrap" Margin="12,0,0,0" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding LineThree}" TextWrapping="NoWrap" Margin="12,-6,0,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</controls:PivotItem>
</controls:Pivot>
</Grid>
<!--Sample code showing usage of ApplicationBar-->
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1" Click="ApplicationBarIconButton_Click"/>
<shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
<shell:ApplicationBar.MenuItems>
<shell:ApplicationBarMenuItem Text="MenuItem 1"/>
<shell:ApplicationBarMenuItem Text="MenuItem 2"/>
</shell:ApplicationBar.MenuItems>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
Filter
CollectionViewSource
上的属性在
Resources
上面的部分被分配了一个过滤器处理程序,它筛选那些具有
IsSelected
的项目。设置为真:
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
DataContext = App.ViewModel;
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
CollectionViewSource isSelectedListView = this.Resources["IsSelectedCollectionView"] as CollectionViewSource;
if (isSelectedListView != null)
{
isSelectedListView .Source = App.ViewModel.Items;
}
}
}
private void CollectionViewSource_SelectedListFilter(object sender, System.Windows.Data.FilterEventArgs e)
{
e.Accepted = ((ItemViewModel)e.Item).IsSelected;
}
private void ApplicationBarIconButton_Click(object sender, EventArgs e)
{
ItemViewModel item = App.ViewModel.Items[App.ViewModel.Items.Count - 1];
item.IsSelected = !item.IsSelected;
}
}
CollectionViewSource
并将其数据源设置为
ObservableCollection<T>
列表,以便有可以进行过滤的基础数据。
ObservableCollection<T>
中。其中有
IsSelected
true,显示在第二个 Pivot 中:
IsSelected
ObservableCollection<T>
中最后一项的属性单击时(请参阅 MainPage.xaml.cs 中的最后一个函数)。
IsSelected
属性设置为 true,但是第二个 Pivot 不显示此更改的项目。我可以看到
NotifyPropertyChanged()
处理程序在项目上被触发,但是集合没有选择这个事实,因此 Pivot 2 中的列表框不会更改以反射(reflect)应该有一个新项目添加到集合中的事实。
CollectionViewSource
基于排序,那么当排序中使用的项目的属性发生变化时,集合的排序顺序应该也反射(reflect)这一点))
最佳答案
我必须处理这个问题,虽然“Refresh()”解决方案运行良好,但执行时间很长,因为它仅针对一个项目属性更改事件刷新整个列表。不是很好。并且在每 1 秒实时数据进入集合的场景中,我让你想象一下如果你使用这种方法,用户体验的结果:)
我想出了一个解决方案,其基础是:将项目添加到包含在 Collection View 中的集合时,然后由过滤器谓词评估该项目,并根据此结果在 View 中显示或不显示。
因此,我没有调用 refresh(),而是模拟了一个对象的插入,该对象更新了它的属性。通过模拟对象的插入,它将由过滤谓词自动评估,而无需通过刷新来刷新整个列表。
这是执行此操作的代码:
派生的可观察集合:
namespace dotnetexplorer.blog.com
{
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
/// <summary>
/// Derived class used to be able to manage filter application when a collection item property changed
/// whithout having to do a refresh
/// </summary>
internal sealed class CustomObservableCollection : ObservableCollection<object>
{
/// <summary>
/// Initializes a new instance of the <see cref = "CustomObservableCollection " /> class.
/// </summary>
public CustomObservableCollection ()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CustomObservableCollection "/> class.
/// </summary>
/// <param name="source">
/// The source.
/// </param>
public CustomObservableCollection (IEnumerable<object> source)
: base(source)
{
}
/// <summary>
/// Custom Raise collection changed
/// </summary>
/// <param name="e">
/// The notification action
/// </param>
public void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e)
{
OnCollectionChanged(e);
}
}
}
private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
// To avoid doing a refresh on a property change which would end in a very hawful user experience
// we simulate a replace to the collection because the filter is automatically applied in this case
int index = _substituteSource.IndexOf(sender);
var argsReplace = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace,
new List<object> { sender },
new List<object> { sender }, index);
_substituteSource.RaiseCollectionChanged(argsReplace);
}
}
}
关于silverlight - 当单个项目的属性更改时,如何自动更新 CollectionViewSource 上的过滤器和/或排序顺序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3771556/
你能比较一下属性吗 我想禁用文本框“txtName”。有两种方式 使用javascript,txtName.disabled = true 使用 ASP.NET, 哪种方法更好,为什么? 最佳答案 我
Count 属性 返回一个集合或 Dictionary 对象包含的项目数。只读。 object.Count object 可以是“应用于”列表中列出的任何集合或对
CompareMode 属性 设置并返回在 Dictionary 对象中比较字符串关键字的比较模式。 object.CompareMode[ = compare] 参数
Column 属性 只读属性,返回 TextStream 文件中当前字符位置的列号。 object.Column object 通常是 TextStream 对象的名称。
AvailableSpace 属性 返回指定的驱动器或网络共享对于用户的可用空间大小。 object.AvailableSpace object 应为 Drive 
Attributes 属性 设置或返回文件或文件夹的属性。可读写或只读(与属性有关)。 object.Attributes [= newattributes] 参数 object
AtEndOfStream 属性 如果文件指针位于 TextStream 文件末,则返回 True;否则如果不为只读则返回 False。 object.A
AtEndOfLine 属性 TextStream 文件中,如果文件指针指向行末标记,就返回 True;否则如果不是只读则返回 False。 object.AtEn
RootFolder 属性 返回一个 Folder 对象,表示指定驱动器的根文件夹。只读。 object.RootFolder object 应为 Dr
Path 属性 返回指定文件、文件夹或驱动器的路径。 object.Path object 应为 File、Folder 或 Drive 对象的名称。 说明 对于驱动器,路径不包含根目录。
ParentFolder 属性 返回指定文件或文件夹的父文件夹。只读。 object.ParentFolder object 应为 File 或 Folder 对象的名称。 说明 以下代码
Name 属性 设置或返回指定的文件或文件夹的名称。可读写。 object.Name [= newname] 参数 object 必选项。应为 File 或&
Line 属性 只读属性,返回 TextStream 文件中的当前行号。 object.Line object 通常是 TextStream 对象的名称。 说明 文件刚
Key 属性 在 Dictionary 对象中设置 key。 object.Key(key) = newkey 参数 object 必选项。通常是 Dictionary 
Item 属性 设置或返回 Dictionary 对象中指定的 key 对应的 item,或返回集合中基于指定的 key 的&
IsRootFolder 属性 如果指定的文件夹是根文件夹,返回 True;否则返回 False。 object.IsRootFolder object 应为&n
IsReady 属性 如果指定的驱动器就绪,返回 True;否则返回 False。 object.IsReady object 应为 Drive&nbs
FreeSpace 属性 返回指定的驱动器或网络共享对于用户的可用空间大小。只读。 object.FreeSpace object 应为 Drive 对象的名称。
FileSystem 属性 返回指定的驱动器使用的文件系统的类型。 object.FileSystem object 应为 Drive 对象的名称。 说明 可
Files 属性 返回由指定文件夹中所有 File 对象(包括隐藏文件和系统文件)组成的 Files 集合。 object.Files object&n
我是一名优秀的程序员,十分优秀!