简而言之:我想声明一个自定义路由事件,同时从声明它的同一个用户控件中监听它。
我想要实现的是拥有一个为某个任务提供请求的用户控件,所以我想到了这个场景:
然后:
它似乎不起作用。它与用户控件声明并引发事件的通常情况有点不同,我知道,所以我做了一些测试。
如何创建自定义路由事件似乎很清楚,这不是我第一次这样做。我创建了一个示例用户控件,这是它背后的代码:
public partial class FuffaControl : UserControl
{
public static readonly RoutedEvent FuffaEvent = EventManager.RegisterRoutedEvent("Fuffa", RoutingStrategy.Bubble, typeof(FuffaEventHandler), typeof(FuffaControl));
// Provide CLR accessors for the event
public event FuffaEventHandler Fuffa
{
add { AddHandler(FuffaEvent, value); }
remove { RemoveHandler(FuffaEvent, value); }
}
public FuffaControl()
{
InitializeComponent();
}
}
到目前为止,这么好。然后,出于测试目的,我已经声明了一个带有自定义控件的窗口和一个按钮。这是窗口的内容:
<Grid>
<local:FuffaControl>
<Grid>
<Button Content="Fuffa" HorizontalAlignment="Center" VerticalAlignment="Center" Click="Button_Click"/>
</Grid>
</local:FuffaControl>
</Grid>
在后面的代码中,我使用AddHandler来监听事件,并在点击按钮时引发事件:
public MainWindow()
{
InitializeComponent();
this.AddHandler(FuffaControl.FuffaEvent, new FuffaEventHandler(OnFuffaEvent));
}
private void Button_Click(object sender, RoutedEventArgs e)
{
RoutedEventArgs newEventArgs = new RoutedEventArgs(FuffaControl.FuffaEvent);
RaiseEvent(newEventArgs);
}
private void OnFuffaEvent(object sender, RoutedEventArgs e)
{
}
有效。它没有多大意义(我的意思是,它不是那么有用),但我只是用它来测试事件本身是否正常工作。好吧,除非C#正在做一些奇怪的事情并切割一些角落,但乍一看,在我看来按钮正在提升一个自定义事件,事件在树上传播(毕竟这是一个冒泡的事件),并且窗口收到它。
所以,接下来我接受AddHandler(...)调用和处理函数并将它们移动到用户控件;现在不是窗口谁听Raisevent(...),但用户控制自己。如果它有效,我有子元素引发一个事件,而父用户控件管理它:
public partial class FuffaControl : UserControl
{
public static readonly RoutedEvent FuffaEvent = EventManager.RegisterRoutedEvent("Fuffa", RoutingStrategy.Bubble, typeof(FuffaEventHandler), typeof(FuffaControl));
// Provide CLR accessors for the event
public event FuffaEventHandler Fuffa
{
add { AddHandler(FuffaEvent, value); }
remove { RemoveHandler(FuffaEvent, value); }
}
public FuffaControl()
{
InitializeComponent();
this.AddHandler(FuffaControl.FuffaEvent, new FuffaEventHandler(OnFuffaEvent));
}
private void OnFuffaEvent(object sender, RoutedEventArgs e)
{
}
}
Nnnnnope。它不起作用。为什么?这有什么问题?为什么用户控件无法收听自己的事件?
答案 0 :(得分:6)
原因在于您如何举起该活动:
.
路由事件(与常规.NET事件一样)具有源(发送者)和参数。您只需指定参数,发件人就是您调用/command 123.5
的控件。你可以从^\/command\s?\d+(\.\d{1,8})?$
课程这样做,因此事件来源将是MainWindow,而不是按钮(按钮根本不会参与你的事件提升代码)。 WPF将从发送方开始搜索处理程序以查找路由事件,然后根据事件类型向上或向下查找层次结构。在您的情况下,事件正在冒泡,因此它将从MainWindow开始搜索树。你的控件是窗口的子控件,因此找不到它的处理程序。
相反,您应该在按钮上调用private void Button_Click(object sender, RoutedEventArgs e)
{
RoutedEventArgs newEventArgs = new RoutedEventArgs(FuffaControl.FuffaEvent);
RaiseEvent(newEventArgs);
}
。然后按钮将成为发件人,它将按预期工作:
RaiseEvent
答案 1 :(得分:1)
乍一看,您似乎正在将UserControl
改为ContentControl
。然而,您可以通过将所有逻辑移动到UC并从窗口的RaiseFuffaEvent
处理程序中调用公共Button_Click
来实现此功能。
<强> FuffaControl.xaml.cs 强>
public partial class FuffaControl : UserControl
{
public FuffaControl()
{
InitializeComponent();
AddHandler(FuffaEvent, new RoutedEventHandler(OnFuffaEvent));
}
public static readonly RoutedEvent FuffaEvent = EventManager.RegisterRoutedEvent(
"Fuffa", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(FuffaControl));
public event RoutedEventHandler Fuffa
{
add { AddHandler(FuffaEvent, value); }
remove { RemoveHandler(FuffaEvent, value); }
}
public void RaiseFuffaEvent()
{
RoutedEventArgs newEventArgs = new RoutedEventArgs(FuffaEvent);
RaiseEvent(newEventArgs);
}
private void OnFuffaEvent(object sender, RoutedEventArgs e)
{
}
}
通过RaiseFuffaEvent
的这种实现,其他控件仍然可以监听事件,即使它是从窗口代码后面引发的。
<强> Window.xaml 强>
<Window
...>
<Grid>
<local:FuffaControl x:Name="fuffa">
<Button Content="Fuffa" HorizontalAlignment="Center" VerticalAlignment="Center" Click="Button_Click"/>
</local:FuffaControl>
</Grid>
</Window>
<强> Window.xaml.cs 强>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
fuffa.RaiseFuffaEvent();
}
}
为了完整性,在“正常”UserControl
中,您可以将按钮放在FuffaControl.xaml
中,并在Button_Click
中设置FuffaControl.xaml.cs
处理程序。