在Windows.Forms应用程序中使用WeakEventManager

时间:2009-08-19 13:15:25

标签: c# .net events weak-events weakeventmanager

在Windows.Forms应用程序中使用此处所述的弱事件http://wekempf.spaces.live.com/blog/cns!D18C3EC06EA971CF!373.entry时,WeakEventManager会泄漏WeakReference对象。 我认为这是因为没有WPF消息循环,所以从不执行CleanupOperation,尽管在WeakEventManager.ProtectedAddListener中调用了ScheduleCleanup。

作为一种解决方法,我实现了类似的清理功能:

internal bool Cleanup()
{
    // The following is equivalent to 
    //    return this.Table.Purge(false);
    // but we need to use reflection to access the private members.

    PropertyInfo pi = typeof(WeakEventManager).GetProperty("Table", BindingFlags.Instance | BindingFlags.NonPublic);
    if (pi == null)
        return false;
    object table = pi.GetValue(this, null);
    MethodInfo mi = table.GetType().GetMethod("Purge", BindingFlags.Instance | BindingFlags.NonPublic);
    if (mi == null)
        return false;
    return (bool)mi.Invoke(table, new object[] { false });
}

并在每次例如第16次致电ProtectedAddListener

这很有效,但显然我喜欢避免这种(ab)使用反射。

所以我的问题是:

  1. 有没有办法使用公共/受保护成员实现清理功能? WeakEventManager.Purge可能很有用,但我不知道如何使用它。
  2. 有一种在基于Windows.Forms的应用程序中运行WPF消息循环的简单方法吗?

1 个答案:

答案 0 :(得分:2)

此代码构建一个可以保持缓存的静态函数。它会在每次运行时消除反射的痛苦,并且基本上就是你所拥有的。将其缓存到某处并通过每次传入弱事件管理器来调用它。除了一次点击(在建设/编译期间),没有进一步的反思。

    using System.Windows;
    using System.Linq.Expressions;
    using Expression = System.Linq.Expressions.Expression;

    static void Main(string[] args)
    {
        Func<WeakEventManager, bool> cleanUpFunction = BuildCleanUpFunction();
    }

    private static Func<WeakEventManager, bool> BuildCleanUpFunction()
    {
        ParameterExpression managerParameter = Expression.Parameter(
            typeof(WeakEventManager),
            "manager"
        );
        return Expression.Lambda<Func<WeakEventManager, bool>>(
            Expression.Call(
                Expression.Property(
                    managerParameter,
                    "Table"
                ),
                "Purge",
                Type.EmptyTypes,
                Expression.Default(
                    typeof(bool)
                )
            ),
            managerParameter
        ).Compile();
    }