在我的 WP8 C#/ XAML项目中我正在使用事件通知我的视图已完成某些异步过程。
我有两种代表。
我正在从这些代表创建事件,并且有几个人通知我的观点,某些操作已完成或已启动(为了显示进度条,导航到另一个页面,禁用某些控件等)。
为了引发这些事件,我想创建一个私有的“通知方法”,这将提升这些代表。
我想到的方法在下面的代码示例中为fireUpEvent
方法。
ReturnState枚举
public enum ReturnState : int
{
state1 = 0,
... //for the purpose of the presentation
state6 = 15
...
}
事件的定义&方法
public delegate void LoadingStartedEventHandler();
public delegate void LoadingFinishedEventHandler(ReturnState state);
public event LoadingStartedEventHandler LoadingStarted;
public event LoadingFinishedEventHandler LoadingFinished;
private void fireUpEvent(Action<ReturnState> action, Returnstate parameter)
{
if(action != null)
{
action(parameter);
}
}
private void fireUpEvent(Action action)
{
if(action != null)
{
action();
}
}
用法
fireUpEvent(LoadingFinished, ReturnState.state1);
问题是,当我尝试编译时,我得到一个错误说:
Argument1: Cannot convert from 'XXXX.YYYY.SomeClass.LoadingFinishedEventHandler' to 'System.Action<XXXX.YYYY.Returnstate>'
我尝试使用谷歌搜索,但没有找到任何有用的东西。
为什么不能兑换?
我想在这些方法中Action<ReturnState>
和Action
而不是特定的代表,是否可能?
我应该使用Action
之类的任何其他“类型”吗?
我从这个“grooup”中知道的只有两个是Func
&amp; Action
,还有其他人吗?
答案 0 :(得分:10)
回答这一行:
为什么不能兑换?
它们是不同的委托类型,并且在不同的委托类型之间没有引用转换(使用泛型方差的通用委托类型除外)。您可以像Action
这样创建LoadingStartedEventHandler
:
LoadingStartedEventHandler handler = ...; // Whatever
Action action = new Action(handler);
...你可以反过来做同样的事情,并使用你的其他代表类型和Action<T>
。但实际上没有必要这样做。
我想在这些方法中
Action<ReturnState>
和Action
而不是特定的代表,是否可能?
是的 - 只是不要使用这些代表声明事件,实际上根本没有声明代理人!
你可以改变这个:
public delegate void LoadingStartedEventHandler();
public delegate void LoadingFinishedEventHandler(ReturnState state);
public event LoadingStartedEventHandler LoadingStarted;
public event LoadingFinishedEventHandler LoadingFinished;
对此:
public event Action LoadingStarted;
public event Action<ReturnState> LoadingFinished;
请注意,这违反了.NET conventions on events,请注意。按照惯例,使用委托声明事件,其中第一个参数是类型为object
的“发送者”,第二个参数是从EventArgs
(或EventArgs
本身派生的类型)。这对你来说是否重要是由你来决定的。如果您决定遵循约定,您基本上想要创建一个派生自EventArgs
持有ReturnState
的类型,然后将事件替换为:
public event EventHandler LoadingStarted;
public event EventHandler<ReturnStateEventArgs> LoadingFinished;
将帮助方法更改为:
private void RaiseEvent(EventHandler<TEventArgs> handler,
TEventArgs parameter)
{
if(handler != null)
{
handler(this, parameter);
}
}
private void RaiseEvent(EventHandler handler)
{
if(handler != null)
{
handler(this, EventArgs.Empty);
}
}
(我已经修改了方法名称以遵循.NET约定,并使用.NET术语来处理事件,这些事件是“引发”而不是“激发”。)
答案 1 :(得分:2)
先生。 Skeet总能得到很好的答案。在这里,我将提供您在问题中所述内容的另一种解决方案。
对于这两个:
- 为什么不能兑换?
- 我想在那些方法中采取行动和行动,而不是特定的代表,是否可能?
醇>
先生。 Skeet已经回答了。
对于这两个:
- 我应该使用像Action这样的其他“类型”吗?
- 我从这个“grooup”中知道的只有两个是Func&amp;行动,还有其他人吗?
醇>
您的fireUpEvent
方法可能不应该接受一种简单的委托作为脆弱的设计。但它有可能做到。
C#中所有委托类型的最终基本类型是Delegate
; Delegate
的限制是它不能是泛型类型和方法中的where
约束。
要回答这个问题(无论设计有什么关系),你可以说:
private void fireUpEvent(
Delegate loadingEvent, ReturnState? parameter=null) {
if(null!=loadingEvent) {
foreach(var d in loadingEvent.GetInvocationList()) {
var args=null!=parameter?new object[] { parameter }:null;
d.Method.Invoke(d.Target, args);
}
}
}
而不是您问题中的原始两种方法,Target
是拥有该方法的对象,如果它是静态方法,则会被视为this
,null
。 args
是传递给方法的参数列表。
这只是一种你可以实现的方式,而且我很确定Skeet先生的答案绝对更好。