【问题标题】:Silverlight UI not unsubscribing from PropertyChanged eventsSilverlight UI 未取消订阅 PropertyChanged 事件
【发布时间】:2011-04-30 15:55:59
【问题描述】:

我有一个数据绑定的 UI。当我更改基础数据时,UI 更新正常,但控件似乎仍然订阅了我的 PropertyChanged 事件。

我有以下:

  • 绑定到 ListA 的 ItemsControl

  • 每个项目 ListA 都包含一个子列表 使用另一个显示的 ListB 项目控制

  • ListB 中的每个项目都使用 绑定到字符串属性的文本框 通过 INotifyPropertyChanged

这是 XAML:

<UserControl x:Class="SilverlightBindingTest.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <UserControl.Resources>

        <DataTemplate x:Key="DataTempl" >
            <TextBox Text="{Binding Value, Mode=TwoWay}"/>
        </DataTemplate>

        <DataTemplate x:Key="PageTempl" >
            <ItemsControl ItemsSource="{Binding Datas}" ItemTemplate="{StaticResource DataTempl}"></ItemsControl>
        </DataTemplate>

    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White">
        <StackPanel>
            <ItemsControl ItemsSource="{Binding Pages}" ItemTemplate="{StaticResource PageTempl}"></ItemsControl>
            <Button Content="Swap list" Click="ButtonClick1"></Button>
            <Button Content="Change base data" Click="ButtonClick2"></Button>
        </StackPanel>
    </Grid>
</UserControl>

代码如下:

using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Collections.Generic;

namespace SilverlightBindingTest
{
   public partial class MainPage : INotifyPropertyChanged
   {
      private List<DataGroupClass> pages1 = new List<DataGroupClass>();
      private List<DataGroupClass> pages2 = new List<DataGroupClass>();

      public MainPage()
      {
         InitializeComponent();
         List<DataClass> group = new List<DataClass>();
         group.Add(new DataClass("value 1"));
         group.Add(new DataClass("value 2"));
         group.Add(new DataClass("value 3"));
         pages1.Add(new DataGroupClass(group));

         group = new List<DataClass>();
         group.Add(new DataClass("value 4"));
         group.Add(new DataClass("value 5"));
         group.Add(new DataClass("value 6"));
         pages2.Add(new DataGroupClass(group));
         DataContext = this;
      }

      private List<DataGroupClass> pages = new List<DataGroupClass>();
      public List<DataGroupClass> Pages
      {
         get { return pages; }
         set
         {
            pages = value;
            PropertyChangedEventHandler h = PropertyChanged;
            if (h != null)
            {
               h(this, new PropertyChangedEventArgs("Pages"));
            }
         }
      }

      private void ButtonClick1(object sender, RoutedEventArgs e)
      {
         Debug.WriteLine("-------------------\n");
         if (Pages == pages1)
         {
            Pages = pages2;
         }
         else
         {
            Pages = pages1;
         }
      }

      private bool toggle;
      private void ButtonClick2(object sender, RoutedEventArgs e)
      {
         if (toggle)
         {
            pages1[0].Datas[0].Value = "tim";
            pages2[0].Datas[0].Value = "lajos";
         }
         else
         {
            pages1[0].Datas[0].Value = "joe";
            pages2[0].Datas[0].Value = "james";
         }
         toggle = !toggle;
      }

      #region INotifyPropertyChanged Members

      public event PropertyChangedEventHandler PropertyChanged;

      #endregion
   }

   public class DataClass : INotifyPropertyChanged
   {
      private string value;
      public string Value
      {
         get
         {
            Debug.WriteLine("Get Value:" + value);
            return value;
         }
         set
         {
            Debug.WriteLine("Set Value: " + this.value + " => " + value);
            this.value = value;
            PropertyChangedEventHandler h = PropertyChanged;
            if (h != null)
            {
               h(this, new PropertyChangedEventArgs("Value"));
            }
         }
      }

      public DataClass(string value)
      {         
         Value = value;
      }

      public event PropertyChangedEventHandler PropertyChanged;
   }

   public class DataGroupClass
   {
      private List<DataClass> datas;
      public List<DataClass> Datas
      {
         get
         {
            Debug.WriteLine("Get Datas");
            return datas;
         }
         set
         {
            Debug.WriteLine("Set Datas");
            datas = value;
         }
      }

      public DataGroupClass(List<DataClass> datas)
      {         
         Datas = datas;
      }
   }
}

这是跟踪输出:

点击“交换列表”十次(一切正常):

 -------------------

 Get Datas
 Get Value:value 1
 Get Value:value 2
 Get Value:value 3
-------------------

 Get Datas
 Get Value:value 4
 Get Value:value 5
 Get Value:value 6
-------------------

 Get Datas
 Get Value:value 1
 Get Value:value 2
 Get Value:value 3
-------------------

 Get Datas
 Get Value:value 4
 Get Value:value 5
 Get Value:value 6
 -------------------

 Get Datas
 Get Value:value 1
 Get Value:value 2
 Get Value:value 3
 -------------------

 Get Datas
 Get Value:value 4
 Get Value:value 5
 Get Value:value 6
 -------------------

 Get Datas
 Get Value:value 1
 Get Value:value 2
 Get Value:value 3
 -------------------

 Get Datas
 Get Value:value 4
 Get Value:value 5
 Get Value:value 6
 -------------------

 Get Datas
 Get Value:value 1
 Get Value:value 2
 Get Value:value 3
 -------------------

 Get Datas
 Get Value:value 4
 Get Value:value 5
 Get Value:value 6
 -------------------

 Get Datas
 Get Value:value 1
 Get Value:value 2
 Get Value:value 3

点击“更改基础数据”(查看多次调用 Get Value):

    -------------------

    Get Datas 
    Get Value:value 1 
    Get Value:value 2 
    Get Value:value 3 
    Get Datas 
    Set Value: value 1 => joe 
    Get Value:joe  
    Get Value:joe 
    Get Value:joe 
    Get Value:joe 
    Get Value:joe 
    Get Value:joe 
    Get Datas 
    Set Value: value 4 => james 
    Get Value:james 
    Get Value:james 
    Get Value:james 
    Get Value:james 
    Get Value:james 

我想我错过了什么,但是什么?

非常感谢任何帮助!

【问题讨论】:

    标签: wpf silverlight data-binding inotifypropertychanged


    【解决方案1】:

    不,你没有错过什么。在您按下“更改基础数据”时,仍有一些 UI 元素未被垃圾收集器收集。 UI 元素仍保留其绑定表达式,而后者又保留属性更改事件。

    最终那些未使用的 UI 元素将被收集并停止监听属性更改事件。

    您可以通过将GC.Collect() 放在您的按钮1 点击代码的末尾来证明这一点(尽管我当然不建议您执行此实际代码)。通过强制收集,您将看到您对 Value 属性的读取次数不会超过一次。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-05
      • 1970-01-01
      • 2010-11-23
      • 1970-01-01
      • 1970-01-01
      • 2018-01-05
      • 2014-10-29
      • 2017-04-25
      相关资源
      最近更新 更多