【问题标题】:Why DataBinding is not propagating to UserControl为什么 DataBinding 不传播到 UserControl
【发布时间】:2016-10-03 20:58:44
【问题描述】:

今天早上我问了一个问题here,做一个简单的工作示例给了我一个与预期不同的行为。

GitHub 上的完整工作示例。主要部分代码如下。

在本例中,该命令永远不会传播到任何 UserControl,如果 UserControl 直接用作 Window 的子级也是如此。如果将 UserControl 用作 ListBox ItemTemplate 的 DataTemplate,它也不起作用。

我还包括一个 hack 按钮来解决命令到达用户控件的问题。黑客来自StackOverflow

但是使用 hack 并不能解释为什么 UserControl 不接收命令(没有它)并且使用这个 hack 也打破了良好编码的第一条规则:“高内聚和低耦合”。应该在窗口代码中使用 hack 以便它管理 UserControl 中的命令,我的想法是它应该默认发生。

为什么命令默认不传播到 UserControl,我应该怎么做才能以干净的方式将命令传播到 UserControl?

注意:在 UserControl 中仅使用一个 CommandBinding(删除一个或另一个)并不能解决问题。

部分代码:

<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>

【问题讨论】:

    标签: c# wpf user-controls datatemplate commandbinding


    【解决方案1】:

    您没有在用户控件上调用命令的原因是您的按钮不在单独的焦点范围内。为了让 WPF 正确地为命令目标获取焦点元素,它需要位于与命令调用控件不同的焦点范围内。

    框架只会从按钮向上遍历视觉树,在其焦点范围内查找命令绑定(在您的情况下,它不会找到任何绑定)。当框架在当前焦点范围内找不到任何命令绑定时,它才会查看焦点元素的父焦点范围(在您的情况下,按钮位于 Window 焦点范围内,它没有父范围,因此搜索将在那里结束)。

    只需在您的StackPanel 上设置FocusManager.IsFocusScope="True" 即可解决此问题。

    您还可以在按钮上指定CommandTarget 属性以指向您的用户控件而不依赖焦点。

    【讨论】:

    • 很好的解释!十分感谢!完美运行。你知道我是否可以在 UserControl 方面做一些事情以确保它始终适用于每种类型的使用吗?虽然它现在工作正常,但我可能想在其他地方使用我的 UserControl,我必须记住这个想法。只在一个公共位置(UserControl)编写代码以确保在每种情况下都能正确使用,这听起来是一种更好的解决方案?
    • 我也用 menuItem 进行了测试,它工作正常可能是因为 Menu 元素具有您向我建议的修复:FocusManager.IsFocusScope 设置为 true?这是我必须知道和记住的事情 ;-) ?
    • @EricOuellet 完全正确。 MenuItems 显示在弹出窗口中,它们有自己的焦点范围。
    猜你喜欢
    • 2018-06-13
    • 1970-01-01
    • 2014-03-31
    • 2011-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-04
    • 1970-01-01
    相关资源
    最近更新 更多