Microsoft.Win32.SystemEvents事件不适用于WeakEventManager

时间:2018-05-08 04:34:02

标签: wpf weak-events weakeventmanager

当我这样做时

WeakEventManager<SystemEvents, EventArgs>
    .AddHandler(null, nameof(SystemEvents.DisplaySettingsChanged), OnDisplaySettingsChanged);

我的OnDisplaySettingsChanged永远不会被调用。但是,如果我通过SystemEvents.DisplaySettingsChanged += OnDisplaySettingsChanged使用普通事件订阅,一切正常。

发生了什么事?

1 个答案:

答案 0 :(得分:1)

原来是WeakEventManager的错。当事件被触发时,它意味着source对于静态事件源将是null(代码摘录自reference source):

protected void DeliverEvent(object sender, EventArgs args)
{
    ListenerList list;
    object sourceKey = (sender != null) ? sender : StaticSource;
    ...

sender null永远不会SystemEvents。相反,它传递SystemEvents的私有实例,WeakEventManager然后假定它是之前不知道的另一个实例,并且不调用处理程序。

以下是我提出的解决方法:

class EventProxy
{
    private readonly Action<EventHandler> _subscribe;
    private readonly Action<EventHandler> _unsubscribe;

    public EventProxy(Action<EventHandler> subscribe, Action<EventHandler> unsubscribe)
    {
        _subscribe = subscribe;
        _unsubscribe = unsubscribe;
    }

    private EventHandler _event;
    public event EventHandler Event
    {
        add
        {
            if (_event == null)
                _subscribe(OnEvent);
            _event += value;
        }
        remove
        {
            // ReSharper disable once DelegateSubtraction
            _event -= value;
            if (_event == null)
                _unsubscribe(OnEvent);
        }
    }

    private void OnEvent(object sender, EventArgs args)
    {
        _event?.Invoke(this, args);
    }
}

用法示例:

var proxy = new EventProxy(h => SystemEvents.DisplaySettingsChanged += h, h => SystemEvents.DisplaySettingsChanged -= h);
WeakEventManager<EventProxy, EventArgs>.AddHandler(proxy, nameof(EventProxy.Event), OnDisplaySettingsChanged);

一些解释:

  • SystemEvents拥有对EventProxy的强引用,WeakEventManager包含对处理程序的弱引用(通过WeakEventManager
  • AddHandler订阅EventProxy内的事件时,代理订阅原始事件
  • WeakEventManager充当静态事件和处理程序之间的代理,在原始事件触发时调用处理程序
  • 收集处理程序后,public class B1ITEM1L3 extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate( savedInstanceState ); setContentView( R.layout.activity_b1_item1_l3 ); JSONArray jsonArray=getJSonData( "B1ITEM1DATA.json" ); ArrayList<JSONObject> listItems=getArrayListFromJSONArray(jsonArray); ListView listV= findViewById(R.id.list_viewL3ITEM1); ListAdapter adapter = new ListadapterB1ITEM1 (this,R.layout.list_layoutb1item1,R.id.textView,listItems); listV.setAdapter(adapter); } private JSONArray getJSonData(String fileName){ JSONArray jsonArray=null; try { InputStream is = getResources().getAssets().open(fileName); int size = is.available(); byte[] data = new byte[size]; is.read(data); is.close(); String json = new String(data, "UTF-8"); jsonArray=new JSONArray(json); }catch (IOException e){ e.printStackTrace(); }catch (JSONException je){ je.printStackTrace(); } return jsonArray; } private ArrayList<JSONObject> getArrayListFromJSONArray(JSONArray jsonArray){ ArrayList<JSONObject> aList= new ArrayList<>(); try { if (jsonArray != null) { for (int i = 0; i < jsonArray.length(); i++) { aList.add(jsonArray.getJSONObject(i)); } } }catch (JSONException je){je.printStackTrace();} return aList; } public void opencamera(View view) { Intent intent = new Intent( MediaStore.ACTION_IMAGE_CAPTURE ); startActivity( intent ); } } 最终将运行清理,发现处理程序已死并取消订阅
  • 这将导致代理取消订阅原始事件,并最终由GC收集