我正在准备一个包含多个对象的应用程序,每个对象都有一个整数 id 和字符串数据。我希望具有相同 id 的对象的数据相同。我将把这个对象称为 SharedObject (这个对象就像一些数据库表的 ViewModel)。
有人可能会说这很容易。您可以创建单个对象并在每次需要时引用它。但实际上这种方式对我不起作用,因为我无法预测创建对象的时间和地点。
因此,为了解决这个问题,我决定在 SharedObject 类中放置一个静态事件,并在任何 SharedObject 数据发生更改时调用它(例如 INotifyPropertyChanged 中的 PropertyChanged 事件,但我的是静态的。这将使它对 SharedObject 的每个实例可见),但是问题是我最终得到了一个充满内存泄漏的程序!
昨晚整理了一下,不得不使用弱事件模式来解决内存泄漏问题。
我昨晚在网上搜索了弱事件模式的完整实现,但最终我什么也没有或删除了页面。
最后我想出了如何使用弱事件模式来做到这一点,并创建了一个测试项目来测试这种方法,但它不起作用,无法调用 ReceiveWeakEvent 事件。
我错过了什么吗?或者实现这种模式的正确方法是什么?
顺便说一句,我正在使用 .net 4,因为我需要我的应用程序支持 Win XP(这是我的客户需要的,不要问我),所以我不能使用通用的 WeakEventManager 类。
很抱歉发了这么长的帖子,但这个问题让我把头发扯掉了,在此先感谢。
这是完整的应用程序代码:
共享对象类:
public class SharedObject :INotifyPropertyChanged,IWeakEventListener
{
static WaekEvent sheardEvent = new WaekEvent();
public event PropertyChangedEventHandler PropertyChanged;
public int ID { get; private set; }
public SharedObject(int id)
{
this.ID = id;
SharedWeakEventManager.AddListener(sheardEvent, this);
}
string data;
public string Data
{
get
{
return data;
}
set
{
if(value != data)
{
data = value;
OnPropertyChanged("Data");
sheardEvent.RiseSharedEvent(this, new PropertyChangedEventArgs("Data"));
}
}
}
protected virtual void OnPropertyChanged(string propName)
{
PropertyChangedEventHandler handler;
lock (this)
{
handler = PropertyChanged;
}
if (handler != null)
handler.Invoke(this, new PropertyChangedEventArgs(propName));
}
void OnSharedPropertyChaingo(object sender,PropertyChangedEventArgs e)
{
SharedObject s = sender as SharedObject;
if (s == null || s.ID != ID)
return;
data = s.Data;
OnPropertyChanged("Data");
}
public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
{
if(managerType == typeof(SharedWeakEventManager) && sender is SharedObject)
{
OnSharedPropertyChaingo(sender, e as PropertyChangedEventArgs);
}
return false;
}
}
WaekEvent 和 SharedWeakEventManager 类:
public class SharedObject
{
public event EventHandler SharedEvent;
public void RiseSharedEvent(object sender, EventArgs args)
{
if (SharedEvent != null)
SharedEvent.Invoke(sender, args);
}
}
public class SharedWeakEventManager : WeakEventManager
{
public static SharedWeakEventManager CurrentManager
{
get
{
var manager_type = typeof(SharedWeakEventManager);
var manager = WeakEventManager.GetCurrentManager(manager_type) as SharedWeakEventManager;
if (manager == null)
{
manager = new SharedWeakEventManager();
WeakEventManager.SetCurrentManager(manager_type, manager);
}
return manager;
}
}
public static void AddListener(WaekEvent source, IWeakEventListener listener)
{
CurrentManager.ProtectedAddListener(source, listener);
}
public static void RemoveListener(WaekEvent source, IWeakEventListener listener)
{
CurrentManager.ProtectedRemoveListener(source, listener);
}
protected override void StartListening(object source)
{
((WaekEvent)source).SharedEvent += this.DeliverEvent;
}
protected override void StopListening(object source)
{
((WaekEvent)source).SharedEvent -= this.DeliverEvent;
}
}
MainWindow 的 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">
<Grid>
<ListView x:Name="View" Margin="10,49,10,10" SelectionChanged="ListView_SelectionChanged">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" Width="100" DisplayMemberBinding="{Binding ID}"/>
<GridViewColumn Header="Data" Width="100" DisplayMemberBinding="{Binding Data}"/>
</GridView>
</ListView.View>
</ListView>
<Button Content="New" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="10,13.01,0,0" Click="Button_Click"/>
<TextBox x:Name="IDText" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="92" Margin="136.2,11,0,0"/>
<TextBox x:Name="DataText" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="92" Margin="280.799,11,0,0" TextChanged="DataText_TextChanged"/>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="ID" VerticalAlignment="Top" Margin="119.593,14,0,0"/>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Data" VerticalAlignment="Top" Margin="251.106,15.01,0,0"/>
<Button Content="Remove" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="377.799,12,0,0" Click="Button_Click_1"/>
</Grid>
主窗口类:
public partial class MainWindow : Window
{
private ObservableCollection<SharedObject> sharedObjects;
public ObservableCollection<SharedObject> SharedObjects
{
get
{
if (sharedObjects == null)
sharedObjects = new ObservableCollection<SharedObject>();
return sharedObjects;
}
}
public SharedObject SelelectedObject { get; set; }
public MainWindow()
{
InitializeComponent();
View.ItemsSource = SharedObjects;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
int id;
if (!int.TryParse(IDText.Text, out id))
return;
SharedObject x = new SharedObject(id);
x.Data = DataText.Text;
SharedObjects.Add(x);
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
if (SelelectedObject == null)
return;
SharedObjects.Remove(SelelectedObject);
SelelectedObject = null;
}
private void DataText_TextChanged(object sender, TextChangedEventArgs e)
{
if (SelelectedObject != null)
SelelectedObject.Data = DataText.Text;
}
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
SelelectedObject = View.SelectedItem as SharedObject;
if (SelelectedObject == null)
return;
IDText.Text = SelelectedObject.ID.ToString();
DataText.Text = SelelectedObject.Data;
}
}