积极答复者
ObservableCollection 问题

问题
-
在很多时候用ObservableCollection<T>就直接刷新整个ObservableCollection<T>.
但奇怪的事为什么无法触发改变事件.通知绑定的控件1 public partial class TestDatagrid : UserControl 2 { 3 public TestDatagrid() 4 { 5 InitializeComponent(); 6 listpeople = new ObservableCollection<people>(); 7 DispatcherTimer timer = new DispatcherTimer(); 8 timer.Interval = TimeSpan.FromSeconds(2); 9 timer.Tick += new EventHandler(timer_Tick); 10 timer.Start(); 11 } 12 13 void timer_Tick(object sender, EventArgs e) 14 { 15 WebClient webclient = new WebClient(); 16 webclient.OpenReadCompleted += new OpenReadCompletedEventHandler(webclient_OpenReadCompleted); 17 webclient.OpenReadAsync(new Uri("ITMS.xml", UriKind.Relative)); 18 19 } 20 21 void webclient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) 22 { 23 XElement xml = XElement.Load(System.Xml.XmlReader.Create(e.Result)); 24 var query = from x in xml.DescendantsAndSelf("people") 25 select new people 26 { 27 name = x.Attribute("name").Value, 28 value = x.Attribute("value").Value, 29 }; 30 31 ObservableCollection<people> ops = new ObservableCollection<people>(); 32 foreach (people p in query.ToList()) 33 { 34 ops.Add(p); //那为什么我换成listpeople.add();又可以刷新绑定的控件呢. 如果想整个刷新该如何处理 35 } 36 listpeople = ops;//listpeople更新之后无法通知DataGrid dg 刷新新的数据.有时候还报错(往上看) 37 38 } 39 ObservableCollection<people> listpeople; 40 private void createDatagrid_Click(object sender, RoutedEventArgs e) 41 { 42 DataGrid dg = new DataGrid(); 43 DataGridTextColumn namecol = new DataGridTextColumn(); 44 namecol.Header = "姓名"; 45 namecol.Binding = new System.Windows.Data.Binding("name"); 46 DataGridTextColumn agecol = new DataGridTextColumn(); 47 agecol.Header = "年龄"; 48 agecol.Binding = new System.Windows.Data.Binding("value"); 49 dg.AutoGenerateColumns = false; 50 dg.Columns.Add(namecol); 51 dg.Columns.Add(agecol); 52 53 listpeople = new ObservableCollection<people>(){new people { name = "Mick", value = "24" }, 54 new people { name = "jack", value = "20" }, 55 new people { name = "tom", value = "29" }}; 56 57 58 dg.ItemsSource = listpeople; 59 60 datagridcontainer.Children.Add(dg); 61 62 } 63 } 64 public class people 65 { 66 public string name { get; set; } 67 public string value { get; set; } 68 }
前台xaml
<StackPanel HorizontalAlignment="Left">
<Button x:Name="createDatagrid" Width="150" Height="20" Margin="10,10,0,0" Click="createDatagrid_Click">
<TextBlock Text="用我来动态创建datagrid"></TextBlock>
</Button>
<Canvas x:Name="datagridcontainer" Background="Red" Margin="5,5,0,0" Height="200" Width="200">
</Canvas>2009年2月22日 16:12
答案
-
你要这么绑定,可以用OneWay绑定模式,这样在你更改数据源的时候,DataGrid就可以自动更新了,实现OneWay绑定,首先要
dtColumn.Binding.Mode = System.Windows.Data.BindingMode.OneWay;
其次,你的绑定源泛型类需要继承 INotifyPropertyChanged 接口
拿先前那个类为例
1 public class BindString : INotifyPropertyChanged 2 { 3 public event PropertyChangedEventHandler PropertyChanged; 4 public void NotifyPropertyChanged(string propertyName) 5 { 6 if (PropertyChanged != null) 7 { 8 PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 9 } 10 } 11 12 public string A0 13 { 14 get { return strs[0]; } 15 set 16 { 17 strs[0] = value; 18 NotifyPropertyChanged("A0"); 19 } 20 } 21 public string A1 22 { 23 get 24 { 25 return strs[1]; 26 } 27 set 28 { 29 strs[0] = value; 30 NotifyPropertyChanged("A1"); 31 } 32 } 33 34 public string[] strs = new string[1]; 35 }
在你修改A1的属性的时候DataGrid就会自动更新了:)- 已标记为答案 worldman 2009年2月26日 15:00
2009年2月24日 8:27
全部回复
-
3 public TestDatagrid() 4 { 5 InitializeComponent(); 6 listpeople = new ObservableCollection<people>(); 7 DispatcherTimer timer = new DispatcherTimer(); 8 timer.Interval = TimeSpan.FromSeconds(2); 9 timer.Tick += new EventHandler(timer_Tick); 10 timer.Start(); 11 } 12 13 void timer_Tick(object sender, EventArgs e) 14 { 15 WebClient webclient = new WebClient(); 16 webclient.OpenReadCompleted += new OpenReadCompletedEventHandler(webclient_OpenReadCompleted); 17 webclient.OpenReadAsync(new Uri("ITMS.xml", UriKind.Relative)); 18 19 } 20 21 void webclient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) 22 { 23 XElement xml = XElement.Load(System.Xml.XmlReader.Create(e.Result)); 24 var query = from x in xml.DescendantsAndSelf("people") 25 select new people 26 { 27 name = x.Attribute("name").Value, 28 value = x.Attribute("value").Value, 29 }; 30 31 ObservableCollection<people> ops = new ObservableCollection<people>(); 32 foreach (people p in query.ToList()) 33 { 34 ops.Add(p); //那为什么我换成listpeople.add();又可以刷新绑定的控件呢. 如果想整个刷新该如何处理 35 } 36 listpeople = ops;//listpeople更新之后无法通知DataGrid dg 刷新新的数据.有时候还报错(往上看) 37 38 }
在37行加一句 dg.ItemsSource = listpeople;重新绑定下试试2009年2月22日 16:37 -
谢谢版主的意见。
可是在项目中我不并不希望重新去绑定数据。只是想局部更新。比如在绑定树形结构的时候。
一刷新那么所有节点处于闭合状态。 (树形结构绑定的是treeview.itemsource=ObservableCollection<T>)
另外我上面的代码只是想实现客户端实时刷新的效果(文件在服务器上,当时不理解webcilent的使用,调试程序的时候能刷新,一旦部署之后通过客户端访问就没有作用了。一个错误的例子)
现在2个问题。 1 。ObservableCollection<T>.取交集方法(ObservableCollection<T>) 无法取到2个集合的相同元素
(包ObservableCollection<T> A.取差集方法(ObservableCollection<T>B) 和
包ObservableCollection<T> B.取差集方法(ObservableCollection<T>A)) LinQ to object
2。实现服务器上实时获取xml的数据。发送到客户端。! 目前想到是用silverlight功能wcf ,但想确认下。如果 使用的话,部署的服务器(考虑部署到linux上)上是不是要安装.netframework框架啊 ?(关于这个问题我在文字上也说不清楚,求一个大概的思想)
理解的东西: dg.ItemsSource = listpeople; 数据控件已经绑定的集合 如何再吧listpeople去new的话
貌似开辟了一个新的内存了。所以dg.ItemsSource 数据无法刷新,以为他绑定的是以前那个内存数据
不知道理解是否正确2009年2月24日 3:40 -
你要这么绑定,可以用OneWay绑定模式,这样在你更改数据源的时候,DataGrid就可以自动更新了,实现OneWay绑定,首先要
dtColumn.Binding.Mode = System.Windows.Data.BindingMode.OneWay;
其次,你的绑定源泛型类需要继承 INotifyPropertyChanged 接口
拿先前那个类为例
1 public class BindString : INotifyPropertyChanged 2 { 3 public event PropertyChangedEventHandler PropertyChanged; 4 public void NotifyPropertyChanged(string propertyName) 5 { 6 if (PropertyChanged != null) 7 { 8 PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 9 } 10 } 11 12 public string A0 13 { 14 get { return strs[0]; } 15 set 16 { 17 strs[0] = value; 18 NotifyPropertyChanged("A0"); 19 } 20 } 21 public string A1 22 { 23 get 24 { 25 return strs[1]; 26 } 27 set 28 { 29 strs[0] = value; 30 NotifyPropertyChanged("A1"); 31 } 32 } 33 34 public string[] strs = new string[1]; 35 }
在你修改A1的属性的时候DataGrid就会自动更新了:)- 已标记为答案 worldman 2009年2月26日 15:00
2009年2月24日 8:27 -
确实如版主所说.这样就会自动更新! dtColumn.Binding.Mode = System.Windows.Data.BindingMode.OneWay;也是默认的绑定方式.
但我这是这样一个情况. 要从服务器上获取一个实时数据 然后通过获取最新的数据 赋值给 ObservableCollection<T> 来改变刷新绑定的控件
所以好奇的的是 datagrid dg.itemsource = ObservableCollection<T> b 然后把 ObservableCollection<T> b重新赋值 ObservableCollection<T> b =ObservableCollection<T> A;
为什么datagrid dg.itemsource 还是 ObservableCollection<T> b 这时的ObservableCollection<T> b 已经等于 ObservableCollection<T> A了2009年2月24日 14:50 -
哦. 那要是我的控件是TreeView怎么办..如果我刷新平率高..岂不是总处于节点闭合状态.
其实就是像实现实时刷新.控件Treeview控件上的. 所以我老是在想怎么修改ObservableCollection<T> A中的内容.因为我每次刷新我也不知道哪些值改变了
哪些值没改. 所以我又想用ObservableCollection<T> C = ObservableCollection<T> A.Intersect<T>(ObservableCollection<T> B)获取他们集合的交集
ObservableCollection<T> A:表示以前的值
ObservableCollection<T> B:当前获取的值
ObservableCollection<T> C:交集集合
linq to object来进行筛选..然后 从ObservableCollection<T>A中删除ObservableCollection<T>A.Except(ObservableCollection<T> C)的差集
然后从ObservableCollection<T>A中添加ObservableCollection<T>B.Except(ObservableCollection<T> C)的差集
最后我就可以不用重新绑定控件了.实现刷新.
但是linq to object筛选始终无法得到预期的效果..筛选后都为空
不知道在silverlight tookit的控件上这块能不能帮我一下.
还有ScatterSeries上貌似有bug不知道能不能向你反映下.2009年2月24日 15:53 -
如果你可以保证你的新读取数据跟原有数据之间存在冗余,那么就不用新建一个泛型,直接单行绑定,对比修改原有泛型内的对应数值就可以了哦
是个好注意. 但是个人能力有限.!不能完全理解其中的真谛.
慢慢琢磨...谢谢您的答复.!!!Treeview想要保证以前节点打开,必然你新添加的东西要不然为原有打开的子节点,要不然为新的根节点,原有根节点不会动的,也可以全部赋新值,赋值之前把你现有的Treeview的节点打开状态保存一下就好了
赋值之前把你现有的Treeview的节点打开状态保存一下就好了 ...有这个方法吗? 我去查查去..
确实这个问题很棘手.. 多花点功夫去消化.呵呵.!
谢谢为我指了条明路 哈哈.2009年2月24日 16:11