c# – 状态栏记录y的y
我有一个ObservableCollection,它是Grid的DataContext. Grid是插入主窗口的用户控件.
我想在StatusBar中显示’记录x的y’,因此,作为第一步,我尝试使用此XAML在网格中显示它: <TextBlock Grid.Row="2" Grid.Column="3"> <TextBlock Text="{Binding CurrentPosition}" /> <TextBlock Text="{Binding Count}" /> </TextBlock> Count无问题地工作,并在添加新项目时自动更新.我的代码中定义的CurrentPosition不断保持为0. 如何使CurrentPosition自动更新?我希望不必使用INotify **,因为这已经是一个ObservableCollection. 我也没有任何代码隐藏,所以我希望它可以在我的类(或模型)和XAML中实现. 我确实尝试过使用CurrentChanged但没有成功: public MyObservableCollection() : base() { this.GetDefaultView().CurrentChanged += MyObservableCollection_CurrentChanged; } MyObservableCollection: using System; using System.Collections.Generic; using System.Collections.ObjectModel; namespace ToDoApplication.Models { public class MyObservableCollection<T> : ObservableCollection<T> { public MyObservableCollection() : base() { } public MyObservableCollection(List<T> list) : base(list) { } public MyObservableCollection(IEnumerable<T> collection) : base(collection) { } private System.ComponentModel.ICollectionView GetDefaultView() { return System.Windows.Data.CollectionViewSource.GetDefaultView(this); } public int CurrentPosition { get { return this.GetDefaultView().CurrentPosition; } } public void MoveFirst() { this.GetDefaultView().MoveCurrentToFirst(); } public void MovePrevious() { this.GetDefaultView().MoveCurrentToPrevious(); } public void MoveNext() { this.GetDefaultView().MoveCurrentToNext(); } public void MoveLast() { this.GetDefaultView().MoveCurrentToLast(); } public bool CanMoveBack() { return this.CurrentPosition > 0; } public bool CanMoveForward() { return (this.Count > 0) && (this.CurrentPosition < this.Count - 1); } } public enum Navigation { First,Previous,Next,Last,Add } } 更新:我正在添加以下代码作为可能的解决方案,但我不是很喜欢它,我希望更好的一个出现,不需要我使用INotifyPropertyChanged – 我怀疑我将结束重复所有ObservableCollection应该已经具备的功能. (我也不知道为什么我需要重新通知Count更改.) 更新2:以下不是(完整)解决方案,因为它会干扰集合的其他行为(通知),但我保留了它,以防它包含任何有用的信息. namespace ToDoApplication.Models { public class MyObservableCollection<T> : ObservableCollection<T>,INotifyPropertyChanged { public new event PropertyChangedEventHandler PropertyChanged; private int _currentPos = 1; public MyObservableCollection() : base() { this.GetDefaultView().CurrentChanged += MyObservableCollection_CurrentChanged; this.CollectionChanged += MyObservableCollection_CollectionChanged; } public MyObservableCollection(List<T> list) : base(list) { this.GetDefaultView().CurrentChanged += MyObservableCollection_CurrentChanged; this.CollectionChanged += MyObservableCollection_CollectionChanged; } public MyObservableCollection(IEnumerable<T> collection) : base(collection) { this.GetDefaultView().CurrentChanged += MyObservableCollection_CurrentChanged; this.CollectionChanged += MyObservableCollection_CollectionChanged; } void MyObservableCollection_CurrentChanged(object sender,EventArgs e) { this.CurrentPosition = this.GetDefaultView().CurrentPosition; } void MyObservableCollection_CollectionChanged(object sender,System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { RaisePropertyChanged("Count"); } private System.ComponentModel.ICollectionView GetDefaultView() { return System.Windows.Data.CollectionViewSource.GetDefaultView(this); } public int CurrentPosition { get { return _currentPos; } private set { if (_currentPos == value + 1) return; _currentPos = value + 1; RaisePropertyChanged("CurrentPosition"); } } private void RaisePropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this,new PropertyChangedEventArgs(propertyName)); } } public void MoveFirst() { this.GetDefaultView().MoveCurrentToFirst(); } public void MovePrevious() { this.GetDefaultView().MoveCurrentToPrevious(); } public void MoveNext() { this.GetDefaultView().MoveCurrentToNext(); } public void MoveLast() { this.GetDefaultView().MoveCurrentToLast(); } public bool CanMoveBack() { return this.CurrentPosition > 1; } public bool CanMoveForward() { return (this.Count > 0) && (this.CurrentPosition < this.Count); } } public enum Navigation { First,Add } } 有了这个,我可以在网格中显示“第1项3”: <TextBlock Grid.Row="2" Grid.Column="3" x:Name="txtItemOf">Item <TextBlock x:Name="txtItem" Text="{Binding CurrentPosition}" /> of <TextBlock x:Name="txtOf" Text="{Binding Count}" /> </TextBlock> 我不再需要这个TextBlock,因为我可以直接在(主)StatusBar中引用DataContext属性: <StatusBar DockPanel.Dock="Bottom"> Item <TextBlock Text="{Binding ElementName=vwToDo,Path=DataContext.CurrentPosition}" /> Of <TextBlock Text="{Binding ElementName=vwToDo,Path=DataContext.Count}" /> </StatusBar> 问题和解决方案 关注@JMarsch的回答:命名我的属性CurrentPosition正在屏蔽直接从DataContext可用的同名属性,因为绑定是集合的默认视图(具有此属性). 解决方案要么重命名为MyCurrentPosition,要么从StatusBar引用原始属性,或者像我一样,完全删除我的这个属性(和GetDefaultView)的版本:它们没有做任何特别有用的事情. 然后我使用以下简单的ValueConverter将0,1,2,..转换为1,3,..在StatusBar中. [ValueConversion(typeof(int),typeof(int))] class PositionConverter : IValueConverter { public object Convert(object value,Type targetType,object parameter,System.Globalization.CultureInfo culture) { return (int)value + 1; } public object ConvertBack(object value,System.Globalization.CultureInfo culture) { return (int)value - 1; } } 状态栏: <StatusBar DockPanel.Dock="Bottom" x:Name="status"> Item <TextBlock Text="{Binding ElementName=vwToDo,Path=DataContext.CurrentPosition,Converter={StaticResource posConverter}}" /> Of <TextBlock Text="{Binding ElementName=vwToDo,Path=DataContext.Count}" /> </StatusBar> 解决方法
关于数据绑定到集合的一些非常重要的事情是XAML总是数据绑定到集合视图,而不是集合本身.因此,即使您的XAML似乎绑定到集合,在运行时,您实际上绑定到默认集合视图.
这是一个很酷的副作用:collectionview已经有了一个CurrentPosition属性.我认为事情正在打破你,因为你无意中介入了你的集体. 下面是一个非常快速和脏的小程序,它说明了对CurrentPostion和Count的工作绑定,而没有在集合上定义当前位置(因为在封面下,你真的绑定到CollectionView,它已经有一个CurrentPosition属性,通知变化. 运行此程序,注意当您单击增量按钮时,UI会相应更新. 这是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"> <StackPanel x:Name="ContentPanel"> <Button x:Name="IncrementButton" Content="Increment" Click="IncrementButton_Click"/> <StackPanel Orientation="Horizontal"> <TextBlock x:Name="CurrentPositionTextBlock" Text="{Binding CurrentPosition}"/> <TextBlock Text=" / "/> <TextBlock Text="{Binding Count}"/> </StackPanel> </StackPanel> </Window> 这是代码隐藏: using System.Collections.ObjectModel; using System.ComponentModel; using System.Windows; using System.Windows.Data; namespace WpfApplication1 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.Collection = new TestObservableCollection<object>() {new object(),new object(),new object()}; this.ContentPanel.DataContext = this.Collection; } public TestObservableCollection<object> Collection { get; set; } private void IncrementButton_Click(object sender,RoutedEventArgs e) { this.Collection.GetDefaultView().MoveCurrentToNext(); } } public class TestObservableCollection<T> : ObservableCollection<T> { public ICollectionView GetDefaultView() { return CollectionViewSource.GetDefaultView(this); } } } 这里有更多的阅读材料: http://msdn.microsoft.com/en-us/library/ms752347(v=vs.110).aspx http://msdn.microsoft.com/en-us/library/system.windows.data.collectionviewsource(v=vs.110).aspx 编辑 如果你想要进一步证明发生了什么,请将下面的代码粘贴到我的按钮单击处理程序中 – 您将看到文本框绑定的实际对象类型是ListCollectionView,而不是实际的集合: System.Diagnostics.Debug.WriteLine(this.CurrentPositionTextBlock.GetBindingExpression(TextBlock.TextProperty).ResolvedSource.GetType().FullName); (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |