为什么DataBinding没有传播到UserControl [英] Why DataBinding is not propagating to UserControl

查看:76
本文介绍了为什么DataBinding没有传播到UserControl的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天早上,我问了一个问题在这里并做一个简单的工作样本给了我与预期不同的行为。



GitHub 。下面的主要部分代码。



在这种情况下,无论将UserControl直接用作Window的子级,该命令都不会传播到任何UserControl。如果将UserControl用作ListBox ItemTemplate的数据模板,也将不起作用。



我还提供了一个hack按钮来解决命令到达UserControls的问题。黑客来自 StackOverflow



但是,使用hack并不能解释为什么UserControl没有收到Command(没有它),而使用此hack也违反了良好编码的第一条规则:低耦合。为了在UserControl中管理Command,应在窗口代码中使用该hack,我认为默认情况下应如此。



为什么默认情况下该命令未传播到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 = Horizo​​ntal>
< Button Command = local:Commands.CommandTest>将焦点放在TestBlock上,然后单击此处查看命令是否发生< / Button>
< Button Click = AddHack> Hack< / Button>
< / StackPanel>
< / Grid>
< / Window>

UserControl:

 < 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能够正确地为命令目标拾取焦点元素,它需要与命令调用控件处于不同的焦点范围内。



框架只会从按钮的外观上遍历视觉树在其焦点范围内的命令绑定(在您的情况下将找不到任何内容)。当框架在当前焦点范围内未找到任何命令绑定时,仅会查找焦点元素的父焦点范围(在您的情况下,按钮位于 Window 焦点范围内,



只需在您的计算机上设置 FocusManager.IsFocusScope = True StackPanel 将解决此问题。



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

This morning I asked a question here and doing a simple working sample gave me a different behavior than expected.

Full working sample at GitHub. Main partial code below.

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.

I also include a hack button to fix the problem where the Command reach the UserControls. The hack come from StackOverflow.

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.

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?

Note: Using only one CommandBinding (removing one or the other) in the UserControl does not fix the problem .

Partial code:

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

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

解决方案

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.

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

Simply setting FocusManager.IsFocusScope="True" on your StackPanel will fix the issue.

You could also specify CommandTarget property on your buttons to point to your user control and not rely on focus.

这篇关于为什么DataBinding没有传播到UserControl的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆