为什么把一个空操作器上绑定改变它的行为? [英] Why would putting a no-op Converter on a Binding change its behavior?

查看:103
本文介绍了为什么把一个空操作器上绑定改变它的行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在测试我已经建立了一个用户的控制之中,而且我遇到一些莫名其妙的给我。

I'm in the midst of testing a user control I've built, and I'm encountering something that's inexplicable to me.

控件的处理特定的自定义类型的值组合框的延伸。它有是有约束力的目标属性,该属性自定义类型的依赖属性。

The control's an extension of the ComboBox that handles values of a specific custom type. It has a dependency property of that custom type that is the target property of a Binding.

我已经得到了二传手跟踪语句中,我可以看到,该属性设置得到。但它没有出现在我的用户控制。

I've got a trace statement in the setter, and I can see that the property is getting set. But it's not appearing in my user control.

现在,通常我会说,好吧,我在我的用户控件得到了一个错误。我可能会做,虽然我困惑了。但这个问题是不是在我的控制发现的bug。阅读;这里是会很奇怪。

Now, ordinarily I'd say, okay, I've got a bug in my user control. I probably do, though I'm baffled about it. But this question isn't about finding the bug in my control. Read on; here is where it gets weird.

public class DebuggingConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value; // Add the breakpoint here!!
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException("This method should never be called");
    }
}

这背后的想法是,我该转换器添加到我的绑定,并可以设置断点,看被推什么价值了目标。好吧,这工作得很好。我可以看到,值被推出来。

The idea behind this is that I add this converter to my Binding and can set a breakpoint to see what value is being pushed out to the target. Okay, that works just fine. I can see that the value is being pushed out.

在事实上,它的工作原理有点的的罚款。如果DebuggingConverter附着到绑定,用户控制显示值。如果它不是,它没有。

In fact, it works a little too fine. If the DebuggingConverter is attached to the Binding, the user control displays the value. If it's not, it doesn't.

这怎么可能呢?怎么能值转换器,它没有什么影响绑定控件的行为?

How is that even possible? How could a value converter that does nothing affect the behavior of a bound control?

编辑:

这并不是说,它很可能帮助,但这里的用户控件的XAML:

Not that it's likely to help, but here's the XAML for the user control:

<a:CodeLookupBox
    Grid.Column="1"
    Grid.IsSharedSizeScope="True"
    MinWidth="100"
    Style="{Binding Style}">
    <a:CodeLookupBox.CodeLookupTable>
        <Binding Path="Codes" Mode="OneWay"/>
    </a:CodeLookupBox.CodeLookupTable>
    <a:CodeLookupBox.SelectedCode>
        <Binding Path="Value" Mode="TwoWay" ValidatesOnDataErrors="True"/>
    </a:CodeLookupBox.SelectedCode>
</a:CodeLookupBox>

而对第二个绑定转换器,控制行为就像我没有设置选择code 。即使在 OnSelected codePropertyChanged 处理痕迹声明显示, e.Value 确实包含正确的值。发生这种情况而不管转换器的是否连接或不

Without the converter on the second binding, the control behaves as though I didn't set SelectedCode. Even though a trace statement in the OnSelectedCodePropertyChanged handler shows that e.Value does indeed contain the correct value. This happens irrespective of whether the converter's attached or not.

我一直在试图扭转工程师这个问题,一个思想实验:如果你想创建一个绑定用户的控制,其行为改变,如果无操作器连接在其绑定,你会怎么做呢?我不知道有足够的了解结合拿出一个答案。

I've been trying to reverse-engineer this problem with a thought experiment: if you wanted to create a bound user control whose behavior changed if a no-op converter were attached to its binding, how would you do it? I don't know enough about binding to come up with an answer.

推荐答案

好了,好消息是,我知道为什么选择code 没有被设置当我不使用值转换器。坏消息是,我仍然是一个谜,但问题一直推高了食物链了一下,我有一个解决办法。

Well, the good news is, I know why SelectedCode isn't being set when I'm not using a value converter. The bad news is, I still have something of a mystery, but the problem's been pushed up the food chain a bit, and I have a workaround.

本控制实质上是一串由它知道什么样的项目都在它的事实成为可能的附加功能强类型的组合框。在选择code codeLookupTable 属性是强类型的,他们隐藏了底层的SelectedItem 的ItemsSource 属性,哪些不是。 (这,顺便说一句,这就是为什么这是一个用户的控制,而不是组合框的子类,我不希望这些属性是可见的,因为有很多事情可以发生,如果他们得到设置不当,他们没有很好的。)

This control is essentially a strongly-typed combo box with a bunch of additional features that are made possible by the fact that it knows what kind of items are in it. The SelectedCode and CodeLookupTable properties are strongly typed, and they hide the underlying SelectedItem and ItemsSource properties, which aren't. (This, by the way, is why this is a user control and not a subclass of ComboBox; I don't want those properties to be visible because a lot of things can happen if they get set improperly, none of them good.)

下面是发生了什么。这是当值转换器连接调试我输出(数量控制的哈希值code,因为我有一群人,所有的同时得到时绘制程序的初始化):

Here's what's happening. This is my debugging output when the value converter is attached (the number is the hash code of the control, because I've got a bunch of them that all get drawn simultaneously when the program's initialized):

14626603: OnCodeLookupTablePropertyChanged
   CodeLookupTable property set to Proceedings.Model.CodeLookupTable
   box.MainComboBox.ItemsSource = MS.Internal.Data.EnumerableCollectionView
14626603: OnSelectedCodePropertyChanged:
   SelectedCode property set to Unlicensed Driver [VC12500(A)]
   box.MainComboBox.ItemsSource = MS.Internal.Data.EnumerableCollectionView

这是预期的行为。在 codeLookupTable 属性设置,因此设置选择code 到集合中的项目之一正确设置的SelectedItem 于底层组合框

This is the expected behavior. The CodeLookupTable property is set, so setting SelectedCode to one of the items in that collection correctly sets SelectedItem on the underlying ComboBox.

但是,如果没有的值转换器,我们得到这样的:

But without the value converter, we get this:

16143157: OnSelectedCodePropertyChanged:
   SelectedCode property set to Unlicensed Driver [VC12500(A)]
   box.MainComboBox.ItemsSource = 
16143157: OnCodeLookupTablePropertyChanged
   CodeLookupTable property set to Proceedings.Model.CodeLookupTable
   box.MainComboBox.ItemsSource = MS.Internal.Data.EnumerableCollectionView

在这里,选择code 属性被设置的的的 codeLookupTable 属性。因此,当该方法尝试设置的SelectedItem 于底层组合框,什么都不会发生,因为的ItemsSource 为空。

Here, the SelectedCode property is being set before the CodeLookupTable property is. So when the method tries to set SelectedItem on the underlying ComboBox, nothing happens, because the ItemsSource is null.

这是问题的根源。我傻傻的假设,以便在绑定更新他们的目标是相同的他们在XAML中声明的顺序。 (其中一个原因,我前pressed绑定的元素,而不是属性是因为元素的XML文档中的顺序是确定的,属性的顺序是没有的。它不喜欢我也没多想此)。这显然不是这样。

And here is the root of the problem. I've foolishly assumed that the order that bindings update their target in is the same as the order they're declared in the XAML. (One of the reasons I've expressed the bindings as elements instead of attributes is because the order of elements in an XML document is deterministic and the order of attributes isn't. It's not like I didn't think about this.) This is apparently not the case.

我也认为,也许少一些愚蠢,在其中绑定更新他们的目标的顺序不依赖于他们是否没有连接的值转换器。嗯,就是这样。我不知道还有什么这取决于

I've also assumed, maybe a little less foolishly, that the order in which bindings update their target isn't dependent on whether or not they have attached value converters. Well, it is. I wonder what else it depends on.

幸运的是,我有办法解决这个问题。由于我的 codeLookup 对象包含一个参考 codeLookupTable ,我可以让选择code 二传手设置 codeLookupTable (因而的ItemsSource )属性第一,如果它尚未设置。这会让这个问题消失,无需贴在绑定一个假值转换器,并希望绑定的行为方式不会改变。

Mercifully, I have a way to work around this. Since my CodeLookup object contains a reference to the CodeLookupTable, I can make the SelectedCode setter set the CodeLookupTable (and thus the ItemsSource) property first, if it hasn't already been set. That'll make this problem go away without having to stick a fake value converter on the binding and hope that the way bindings behave never changes.

修改

下面是什么属性声明如下:

Here's what the property declarations look like:

#region SelectedCode

public static readonly DependencyProperty SelectedCodeProperty = DependencyProperty.Register(
    "SelectedCode", typeof(CodeLookup), typeof(CodeLookupBox),
    new FrameworkPropertyMetadata(OnSelectedCodePropertyChanged));

private static void OnSelectedCodePropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
    CodeLookupBox box = (CodeLookupBox)source;
    CodeLookup code = e.NewValue as CodeLookup;
    // this right here is the fix to the original problem:
    if (box.CodeLookupTable == null && code != null)
    {
        box.CodeLookupTable = code.Table;
    }
    box.MainComboBox.SelectedItem = e.NewValue;
}

public CodeLookup SelectedCode
{
    get { return GetValue(SelectedCodeProperty) as CodeLookup; }
    set { SetValue(SelectedCodeProperty, value); }
}

#endregion

#region CodeLookupTable

public static readonly DependencyProperty CodeLookupTableProperty = DependencyProperty.Register(
    "CodeLookupTable", typeof(CodeLookupTable), typeof(CodeLookupBox),
    new FrameworkPropertyMetadata(OnCodeLookupTablePropertyChanged));

private static void OnCodeLookupTablePropertyChanged(DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
    CodeLookupBox box = (CodeLookupBox)source;
    CodeLookupTable table = (CodeLookupTable)e.NewValue;

    box.ViewSource = new CollectionViewSource { Source = table.Codes };
    box.View = box.ViewSource.View;
    box.MainComboBox.ItemsSource = box.View;

}

public CodeLookupTable CodeLookupTable
{
    get { return GetValue(CodeLookupTableProperty) as CodeLookupTable; }
    set { SetValue(CodeLookupTableProperty, value); }
}

#endregion

这篇关于为什么把一个空操作器上绑定改变它的行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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