Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 事件冒泡和RoutedEventArgs源属性_C#_Wpf_Xaml_Events - Fatal编程技术网

C# 事件冒泡和RoutedEventArgs源属性

C# 事件冒泡和RoutedEventArgs源属性,c#,wpf,xaml,events,C#,Wpf,Xaml,Events,我试图在一个简单的WPF应用程序中理解RoutedEventArgs.Source属性。这是XAML代码 <Window x:Class="BubbleDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title

我试图在一个简单的WPF应用程序中理解RoutedEventArgs.Source属性。这是XAML代码

    <Window x:Class="BubbleDemo.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">
    <StackPanel x:Name="stackPanel1" Button.Click="OnOuterButtonClick">
        <Button x:Name="button1" Content="Button 1" Margin="5" />
        <Button x:Name="button2" Margin="5" Click="OnButton2">
            <ListBox x:Name="listBox1">
                <Button x:Name="innerButton1" Content="Inner Button 1" Margin="4" Padding="4" Click="OnInner1" />
                <Button x:Name="innerButton2" Content="Inner Button 2" Margin="4" Padding="4" Click="OnInner2" />
            </ListBox>
        </Button>
        <ListBox ItemsSource="{Binding}" />        
    </StackPanel>
</Window>

这是背后的代码

using System;
using System.Collections.ObjectModel;
using System.Windows;

namespace BubbleDemo
{
    public partial class MainWindow : Window
    {
        private ObservableCollection<string> messages = new ObservableCollection<string>();
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = messages;
        }

        private void AddMessage(string message, object sender, RoutedEventArgs e)
        {
            messages.Add(String.Format("{0}, sender: {1}; source: {2}; original source: {3}",
                message, (sender as FrameworkElement).Name,
                (e.Source as FrameworkElement).Name,
                (e.OriginalSource as FrameworkElement).Name));  
        }

        private void OnOuterButtonClick(object sender, RoutedEventArgs e)
        {
            AddMessage("outer event", sender, e);   
        }

        private void OnInner1(object sender, RoutedEventArgs e)
        {
            AddMessage("inner1", sender, e);
        }

        private void OnInner2(object sender, RoutedEventArgs e)
        {
            AddMessage("inner2", sender, e);

            e.Handled = true;
        }

        private void OnButton2(object sender, RoutedEventArgs e)
        {
            AddMessage("button2", sender, e);
            e.Source = sender;
        }
    }
}
使用系统;
使用System.Collections.ObjectModel;
使用System.Windows;
名称空间BubbleDemo
{
公共部分类主窗口:窗口
{
私有ObservableCollection消息=新ObservableCollection();
公共主窗口()
{
初始化组件();
this.DataContext=消息;
}
私有void AddMessage(字符串消息、对象发送方、路由目标)
{
messages.Add(String.Format(“{0},发送方:{1};源:{2};原始源:{3}”),
消息(发件人作为FrameworkElement)。名称,
(e.Source作为FrameworkElement)。名称,
(e.OriginalSource作为FrameworkElement).Name);
}
专用无效OnOuterButtonClick(对象发送方,路由目标)
{
AddMessage(“外部事件”,发送方,e);
}
私有void OnInner1(对象发送方,RoutedEventArgs e)
{
AddMessage(“inner1”,发送者,e);
}
Inner2上的私有void(对象发送方,RoutedEventArgs e)
{
AddMessage(“inner2”,发送者,e);
e、 已处理=正确;
}
私有void OnButton2(对象发送方,路由目标e)
{
添加消息(“按钮2”,发送者,e);
e、 来源=发送方;
}
}
}
当我单击InnerButton1时,将引发click事件,然后由OnInner1处理程序执行。 之后,执行OnButton2处理程序,该处理程序使用sender参数设置RoutedEventArgs.Source属性。 如果构建并执行此代码,则可以看到输出结果。 当事件到达OnOuterButtonClick处理程序时,底部列表框中的输出应为:

inner1,发送方:innerButton1;资料来源:innerButton1;原始来源:innerButton1
按钮2,发送方:按钮2;资料来源:innerButton1;原始来源:innerButton1
外部事件,发送方:stackPanel1;来源:按钮2;原始来源:innerButton1

但结果是这样的

inner1,发送方:innerButton1;资料来源:innerButton1;原始来源:innerButton1
按钮2,发送方:按钮2;资料来源:innerButton1;原始来源:innerButton1
外部事件,发送方:stackPanel1;来源:innerButton1;原始来源:innerButton1

OnButton2处理程序中重新分配的RoutedEventTargets.Source属性已更改,但返回到OnOutButtonClick处理程序中的innerButton1引用

为什么会发生这种情况?
谢谢

这是一个非常好的问题,我必须研究一下.net的源代码,找出它为什么是这样的:

public object Source
{
  get {return _source;}
  set
  {
    if (UserInitiated && InvokingHandler)
      throw new InvalidOperationException(SR.Get(SRID.RoutedEventCannotChangeWhileRouting));

    ...
  }
}
源属性如下所示:

public object Source
{
  get {return _source;}
  set
  {
    if (UserInitiated && InvokingHandler)
      throw new InvalidOperationException(SR.Get(SRID.RoutedEventCannotChangeWhileRouting));

    ...
  }
}
当事件冒泡或隧道时,每当用户试图设置源时,就会抛出此执行选项

我假设.net Framework中负责此行为的部分也捕获了异常,因此您没有意识到问题。事实上,当试图设置源属性时,当事件冒泡时,调试器显示,即未在设置后立即更改

不幸的是,源代码仅显示事件冒泡(或隧道)时,Microsoft不允许更改源属性,但不允许为什么

如果出于任何原因,您需要获取有关处理事件的Previor处理程序的信息,您可以创建自己的
RoutedEventArgs
扩展,并添加另一个包含此信息的属性


最后,您可以扩展
按钮
类,并引发您自己的事件,其中包含相应的
路由EventTargetSwithHandlerHistory
对象:)

这是一个有趣的问题,需要反映.net
路由
引擎。因此,我发现每个
UIElement
都使用
RaiseEvent()
方法来启动
RoutedEvent
。执行此操作时,它首先构建
EventRoute
。在构建
EventRoute
时,它根据
RoutingStrategy
创建调用处理程序列表,即
Bubble
Tunnel
它在
UIElement
所属的
VisualTree
上下移动,并找出有多少处理程序附加到给定的
RoutedEvent
。显然,对于
innerButton1
innerButton1
有三个处理程序

现在
UIElement
为其
RoutedEvent
获取了
EventRoute
,接下来它在
EventRoute
上调用
InvokeHandlers()
。在调用循环中的处理程序时,
InvokeHandler
args.Source
重置为原始值,如下所示,它为冒泡策略执行此操作

    for (int index = 0; index < this._routeItemList.Count; ++index)
    {
      if (index >= endIndex)
      {
        object bubbleSource = this.GetBubbleSource(index, out endIndex);
        if (!reRaised)
          args.Source = bubbleSource ?? source;
      }
for(int index=0;index=endIndex)
{
object bubbleSource=this.GetBubbleSource(index,out-endIndex);
如果(!重新评级)
args.Source=泡泡源??源;
}
因此,在每次处理程序调用之前,
将重置为其原始值,因此在任何处理程序中对其进行更改都不会传递给下一个处理程序。

相关: