问题描述
今天早上我问了一个问题 这里做一个简单的工作示例给了我一个与预期不同的行为.
This morning I asked a question here and doing a simple working sample gave me a different behavior than expected.
GitHub 上的完整工作示例.主要部分代码如下.
Full working sample at GitHub. Main partial code below.
在这种情况下,命令永远不会传播到任何 UserControl,如果 UserControl 直接用作 Window 的子级.如果将 UserControl 用作 ListBox ItemTemplate 的 DataTemplate,它也不起作用.
In this present case, the command is never propagated to any UserControl, either if the UserControl is use directly as a child of the Window. It also not work if the UserControl is used as a DataTemplate for a ListBox ItemTemplate.
我还包括一个 hack 按钮来解决命令到达用户控件的问题.hack 来自 StackOverflow.
I also include a hack button to fix the problem where the Command reach the UserControls. The hack come from StackOverflow.
但是使用 hack 并不能解释为什么 UserControl 不接收命令(没有它)并且使用这个 hack 也打破了良好编码的第一条规则:高内聚和低耦合".应该在窗口代码中使用 hack 以便它管理 UserControl 中的命令,我的想法是它应该默认发生.
But using the hack does not explain why UserControl does not receive the Command (without it) and using this hack also break the first rule of good coding: "Hi cohesion and Low coupling". The hack should be used in the the window code in order for it to manage the Command in the UserControl, my thought is that it should happen by default.
为什么命令默认不传播到 UserControl,我应该怎么做才能以干净的方式将命令传播到 UserControl?
Why the command is not propagating by default to the UserControl and what should I do to propagate the command to the UserControl in a clean way?
注意:在 UserControl 中仅使用一个 CommandBinding(删除一个或另一个)并不能解决问题.
Note: Using only one CommandBinding (removing one or the other) in the UserControl does not fix the problem .
部分代码:
<Window x:Class="CommandRoutingIntoItemTemplate.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:CommandRoutingIntoItemTemplate"
xmlns:system="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<local:UserControlTest></local:UserControlTest>
<ListBox Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Aqua" BorderThickness="2">
<local:UserControlTest></local:UserControlTest>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Items>
<system:String>1</system:String>
<system:String>2</system:String>
</ListBox.Items>
</ListBox>
<StackPanel Grid.Row="2" Orientation="Horizontal">
<Button Command="local:Commands.CommandTest">Put focus on TestBlock and click here to see if command occurs</Button>
<Button Click="AddHack">Hack</Button>
</StackPanel>
</Grid>
</Window>
用户控制:
<UserControl x:Class="CommandRoutingIntoItemTemplate.UserControlTest"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CommandRoutingIntoItemTemplate"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.CommandBindings>
<CommandBinding Command="local:Commands.CommandTest" CanExecute="CommandTestCanExecuteUserControl" Executed="CommandTestExecuteUserControl"></CommandBinding>
</UserControl.CommandBindings>
<Grid>
<TextBox Text="UserControlTest">
<TextBox.CommandBindings>
<CommandBinding Command="local:Commands.CommandTest" CanExecute="CommandTestCanExecuteTextBox" Executed="CommandTestExecuteTextBox"></CommandBinding>
</TextBox.CommandBindings>
</TextBox>
</Grid>
</UserControl>
推荐答案
您没有在用户控件上调用命令的原因是您的按钮不在单独的焦点范围内.为了让 WPF 正确地为命令目标获取焦点元素,它需要在与命令调用控件不同的焦点范围内.
The reason that you are not getting commands invoked on your user control is that your buttons are not in separate focus scope. For WPF to pick up focused element for command target correctly, it needs to be in separate focus scope from command invoking control.
框架只会从按钮向上遍历可视化树,在其焦点范围内查找命令绑定(在您的情况下,它不会找到任何).当框架在当前焦点范围内找不到任何命令绑定时,它才会查看焦点元素的父焦点范围(在您的情况下,按钮位于没有父范围的 Window
焦点范围中,因此搜索将在那里结束).
Framework will just traverse up visual tree from button looking for command bindings in their focus scope (in your case it won't find any). When framework does not find any command bindings in current focus scope, only then it looks into parent focus scope for focused element (In your case, buttons are in Window
focus scope which has no parent scope so the search will end there).
只需在 StackPanel
上设置 FocusManager.IsFocusScope="True"
即可解决此问题.
Simply setting FocusManager.IsFocusScope="True"
on your StackPanel
will fix the issue.
您还可以在按钮上指定 CommandTarget
属性以指向您的用户控件而不依赖焦点.
You could also specify CommandTarget
property on your buttons to point to your user control and not rely on focus.
这篇关于为什么 DataBinding 不传播到 UserControl的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!