在 WPF 中处理附加事件的附加行为
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15134514/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Attached Behavior handling an Attached Event in WPF
提问by Harsha
I googled regarding this question but couldn't gather any information and I was wondering if it is possible for an attached behavior to handle an attached event??
我用谷歌搜索了这个问题,但无法收集任何信息,我想知道附加行为是否有可能处理附加事件?
I've an event declared in a class and a behavior that I am attaching to a TextBox control, the event will be raised when a button is clicked. I added the handler for this event in my behavior and wrote the logic in the event handler, but it is not executed. So, I was wondering if it is possible for an attached behavior to handle an attached event or not?
我有一个在类中声明的事件和一个附加到 TextBox 控件的行为,单击按钮时将引发该事件。我在我的行为中添加了这个事件的处理程序并在事件处理程序中编写了逻辑,但它没有被执行。所以,我想知道附加行为是否有可能处理附加事件?
class ResetInputEventClass
{
public static readonly RoutedEvent ResetInputEvent = EventManager.RegisterRoutedEvent("ResetInput",
RoutingStrategy.Bubble,
typeof(RoutedEventHandler),
typeof(ResetInputEventClass));
public static void AddResetInputEventHandler(DependencyObject d, RoutedEventHandler handler)
{
UIElement uie = d as UIElement;
if (uie == null)
{
return;
}
uie.AddHandler(ResetInputEventClass.ResetInputEvent, handler);
}
public static void RemoveResetInputEventHandler(DependencyObject d, RoutedEventHandler handler)
{
UIElement uie = d as UIElement;
if (uie == null)
{
return;
}
uie.RemoveHandler(ResetInputEventClass.ResetInputEvent, handler);
}
}
That is my Event class and this is how I am handling it in the behavior
那是我的 Event 类,这就是我在行为中处理它的方式
public class MyBehavior : Behavior<TextBoxBase>
{
public MyBehavior()
{
// Insert code required on object creation below this point.
}
protected override void OnAttached()
{
base.OnAttached();
// Insert code that you would want run when the Behavior is attached to an object.
ResetInputEventClass.AddResetInputEventHandler(AssociatedObject, OnResetInputEvent);
}
protected override void OnDetaching()
{
base.OnDetaching();
// Insert code that you would want run when the Behavior is removed from an object.
ResetInputEventClass.RemoveResetInputEventHandler(AssociatedObject, OnResetInputEvent);
}
private void OnResetInputEvent(Object o, RoutedEventArgs e)
{
//Logic
}
}
Here is my XAML Code:
这是我的 XAML 代码:
<Grid x:Name="LayoutRoot">
<StackPanel>
<TextBox Margin="5" Text="Bye" TextWrapping="Wrap" Width="150">
<i:Interaction.Behaviors>
<local:MyBehavior/>
</i:Interaction.Behaviors>
</TextBox>
<TextBox Margin="5" Text="Bye" TextWrapping="Wrap" Width="150">
<i:Interaction.Behaviors>
<local:MyBehavior/>
</i:Interaction.Behaviors>
</TextBox>
<Button Name="MyButton" Content="Save" Width="50" Height="25" Click="MyButton_Click"/>
</StackPanel>
</Grid>
and I am raising the event in the click event of my button
我在按钮的点击事件中引发事件
private void MyButton_Click(object sender, RoutedEventArgs e)
{
RoutedEventArgs eventArgs = new RoutedEventArgs(ResetInputEventClass.ResetInputEvent,e.OriginalSource);
RaiseEvent(eventArgs);
}
回答by Michael Brown
Your problem is simple. The textbox is registered for the event, but the parent of the textbox is raising it. Thus the handler is never called. You can change the event to make it a Tunneling event instead of Bubbling. Or you can get a handle on your textbox (give it a name and reference in code behind). And have it raise the event.
你的问题很简单。为事件注册了文本框,但文本框的父级正在引发它。因此永远不会调用处理程序。您可以更改事件以使其成为隧道事件而不是冒泡事件。或者你可以得到你的文本框的句柄(在后面的代码中给它一个名称和引用)。并让它引发事件。
<Grid x:Name="LayoutRoot">
<StackPanel>
<TextBox Margin="5" x:Name="byeTextBox" Text="Bye" TextWrapping="Wrap" Width="150">
<i:Interaction.Behaviors>
<local:MyBehavior/>
</i:Interaction.Behaviors>
</TextBox>
<Button Name="MyButton" Content="Save" Width="50" Height="25" Click="MyButton_Click"/>
</StackPanel>
</Grid>
Your code-behind should then look like this
你的代码隐藏应该是这样的
private void MyButton_Click(object sender, RoutedEventArgs e)
{
RoutedEventArgs eventArgs = new RoutedEventArgs(ResetInputEventClass.ResetInputEvent,e.OriginalSource);
byeTextBox.RaiseEvent(eventArgs);
}
and that should fix your problem.
这应该可以解决您的问题。
回答by snowy hedgehog
Of course it is possible. Show me your XAML and I ll tel you how an attached event triggers an attached behavior.
当然这是可能的。向我展示您的 XAML,我将告诉您附加事件如何触发附加行为。
Edited:
编辑:
I dont see the need why you using attached behavior and attached events because you could do everything in code behind.
我不明白为什么您需要使用附加行为和附加事件,因为您可以在后面的代码中完成所有操作。
Here is how to do everything in code behind:
以下是如何在后面的代码中执行所有操作:
Here is XAML without attached properties:
这是没有附加属性的 XAML:
<Grid>
<StackPanel>
<TextBox x:Name="txtBox" Margin="5" Text="Bye" TextWrapping="Wrap" Width="150"/>
<Button Name="MyButton" Content="Save" Width="50" Height="25" Click="MyButton_Click"/>
</StackPanel>
</Grid>
This is code behind.
这是后面的代码。
public MainWindow()
{
InitializeComponent();
}
private void MyButton_Click(object sender, RoutedEventArgs e)
{
this.txtBox.Text = "hello";
}
Because you have set Name property on TextBoxand Buttonyou can access them from code behind in your Window.cs and you can write your handler easly.
因为您已将 Name 属性设置为 onTextBox并且Button您可以从 Window.cs 中的代码访问它们,并且您可以轻松编写处理程序。
Here is how you can do everything with attached properties:
以下是如何使用附加属性执行所有操作:
This is the new XAML for the solution with attached properties. I had to create my custom Interaction because the one you are using is Expression Blend or silverlight and not pure WPF.
这是具有附加属性的解决方案的新 XAML。我必须创建我的自定义交互,因为您使用的是 Expression Blend 或 Silverlight 而不是纯 WPF。
<Grid x:Name="LayoutRoot">
<StackPanel i:Interaction.Behaviour="True">
<TextBox x:Name="txtBox" Margin="5" Text="Bye" TextWrapping="Wrap" Width="150"/>
<Button Name="MyButton" Content="Save" Width="50" Height="25" Click="MyButton_Click"/>
</StackPanel>
</Grid>
I had to set Behavior on Truebecause the default value is falseand when value is not equal to the old then the propery changed event will be called with my custom logic like this:
我必须将 Behavior 设置为打开,True因为默认值是false,当值不等于旧值时,将使用我的自定义逻辑调用属性更改事件,如下所示:
private void MyButton_Click(object sender, RoutedEventArgs e)
{
RoutedEventArgs eventArgs = new RoutedEventArgs(ResetInputEventClass.ResetInputEvent,e.OriginalSource);
RaiseEvent(eventArgs);
}
public class Interaction : DependencyObject
{
// Using a DependencyProperty as the backing store for Behaviour. This enables animation, styling, binding, etc...
public static readonly DependencyProperty BehaviourProperty =
DependencyProperty.RegisterAttached("Behaviour", typeof(bool), typeof(Interaction), new PropertyMetadata(false, new PropertyChangedCallback(OnBehaviourChanged)));
private static void OnBehaviourChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
StackPanel sp = (StackPanel)d;
sp.Dispatcher.BeginInvoke(new Action(() =>
{
TextBox tb = VisualTreeHelper.GetChild(sp, 0) as TextBox;
ResetInputEventClass.AddResetInputHandler(sp, new RoutedEventHandler((o, a) =>
{
// Do here whatever you want, call your custom expressions.
tb.Text = "hello";
}));
}), System.Windows.Threading.DispatcherPriority.Background);
}
}
Inside property changed event which will be called as I already mentioned when I change falseto true. I wait till everything is intialized by telling the dispatcher to execute my code when application is in background. Then I find the TextBoxand inject the handler which will be called when you trigger ResetInputevent.
内部属性更改事件将被调用,正如我在更改false为true. 我通过告诉调度程序在应用程序处于后台时执行我的代码来等待一切都初始化。然后我找到TextBox并注入将在触发ResetInput事件时调用的处理程序。
This is very complicated solution but it will work with attached events and attached properties.
这是一个非常复杂的解决方案,但它适用于附加事件和附加属性。
I highly recommend you to use the code behind for this scenario.
我强烈建议您在这种情况下使用背后的代码。
Also you made a mistake inside your ResetInputEventClassclass. Add and Remove methods are not correctly spelled.
你在ResetInputEventClass课堂上也犯了一个错误。Add 和 Remove 方法拼写不正确。
This is how you should have written them:
这就是你应该如何编写它们:
public static void AddResetInputHandler(DependencyObject d, RoutedEventHandler handler)
{
UIElement uie = d as UIElement;
if (uie == null)
{
return;
}
uie.AddHandler(ResetInputEventClass.ResetInputEvent, handler);
}
public static void RemoveResetInputHandler(DependencyObject d, RoutedEventHandler handler)
{
UIElement uie = d as UIElement;
if (uie == null)
{
return;
}
uie.RemoveHandler(ResetInputEventClass.ResetInputEvent, handler);
}
Have fun, I hope I helped you out.
玩得开心,希望能帮到你。
You could also have achieved this with Commands
你也可以做到这一点 Commands

