未调用 ConvertBack

Posted

技术标签:

【中文标题】未调用 ConvertBack【英文标题】:ConvertBack is not called 【发布时间】:2019-12-25 11:04:06 【问题描述】:

我正在尝试编写一个通用控件,我可以在其中使用转换器传递不同的数据模型(全部实现INotifyPropertyChanged)。数据在控件中传递没有问题并正确显示(其中一些还使用IMultivalueConverts,它可以完美地工作)。虽然修改了数据,但是没有调用MainControl的IMultiValueConverter

通用控件应该只显示从 ObservableCollection 中的坐标计算得到的矩形。

我将 DebugConverters 放在所有绑定上,除了 ConvertBack 到顶部之外,所有内容似乎都已更新。 ListBox 中的 SourceUpdate 也会被调用。

我用不同的 NotifyOn...Updated、Mode 和 UpdateSourceTrigger 尝试了这个转换器,我总是看到控件中的值发生变化,但从来没有看到主控件的 ConvertBack。

使用的部分数据模板(更新正确完成),所有 DegreeTo... 转换器都被双向调用

        <DataTemplate x:Key="RectangleWithLabel">
            <Canvas IsHitTestVisible="True">
                <Rectangle x:Name="RectangleROI" MouseLeftButtonDown="myCanvas_PreviewMouseLeftButtonDown" >
                    <!--
                    <Rectangle.Visibility>
                        <Binding Path="ROI" Converter="StaticResource NullToVisibilityConverter"/>
                    </Rectangle.Visibility>
                    -->
                    <Canvas.Left>
                        <MultiBinding Converter="StaticResource DegreeToScreenPixelConverterH" Mode="TwoWay" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged" >
                            <Binding Path="ROI.Begin.PosH" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" />
                            <Binding Path="DataContext.UsedCoordinateSystem" RelativeSource="RelativeSource FindAncestor, AncestorType=x:Type UserControl" NotifyOnSourceUpdated="True" Mode="TwoWay" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged" />
                        </MultiBinding>
                    </Canvas.Left>
                    <Canvas.Top>
                        <MultiBinding Converter="StaticResource DegreeToScreenPixelConverterV"  Mode="TwoWay" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged">
                            <Binding Path="ROI.Begin.PosV" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"   NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" />
                            <Binding Path="DataContext.UsedCoordinateSystem" RelativeSource="RelativeSource FindAncestor, AncestorType=x:Type UserControl" NotifyOnSourceUpdated="True" Mode="TwoWay" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged"/>
                        </MultiBinding>
                    </Canvas.Top>
                    <Rectangle.Width>
                        <MultiBinding Converter="StaticResource DegreeToScreenPixelWidthConverter"  Mode="TwoWay" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged">
                            <Binding Path="ROI.Begin.PosH" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" />
                            <Binding Path="ROI.End.PosH" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"   NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" />
                            <Binding Path="DataContext.UsedCoordinateSystem" RelativeSource="RelativeSource FindAncestor, AncestorType=x:Type UserControl" NotifyOnSourceUpdated="True" Mode="TwoWay" NotifyOnTargetUpdated="True"/>
                        </MultiBinding>
                    </Rectangle.Width>
                    <Rectangle.Height>
                        <MultiBinding Converter="StaticResource DegreeToScreenPixelHeightConverter"  Mode="TwoWay" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged">
                            <Binding Path="ROI.Begin.PosV" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"   NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True"/>
                            <Binding Path="ROI.End.PosV" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"   NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" />
                            <Binding Path="DataContext.UsedCoordinateSystem" RelativeSource="RelativeSource FindAncestor, AncestorType=x:Type UserControl" NotifyOnSourceUpdated="True" Mode="TwoWay" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged"/>
                        </MultiBinding>
                    </Rectangle.Height>
                    <Rectangle.Fill>#33FF0000</Rectangle.Fill>
                    <Rectangle.Stroke>#FF00FF00</Rectangle.Stroke>
                    <Rectangle.IsHitTestVisible>true</Rectangle.IsHitTestVisible>
                </Rectangle>

包含所有数据的列表视图:

<ListView ItemsSource="Binding Rectangles, Mode=TwoWay, NotifyOnTargetUpdated=True, NotifyOnSourceUpdated=True, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnExceptions=True"   x:Name="listBox" Width="Binding ActualWidth, ElementName=ImageControl, Mode=OneWay,UpdateSourceTrigger=PropertyChanged" Height="Binding ActualHeight, ElementName=ImageControl, Mode=OneWay,UpdateSourceTrigger=PropertyChanged" Background="x:Null" BorderBrush="x:Null" Foreground="x:Null" ItemTemplate="StaticResource RectangleWithLabel" MouseMove="ListBox_MouseMove" DataContextChanged="ListBox_DataContextChanged" SourceUpdated="ListBox_SourceUpdated" IsSynchronizedWithCurrentItem="True" TargetUpdated="ListBox_TargetUpdated"  />

从父级调用 ImageViewer,这里转换器在到 ImageViewer 的途中被调用,但从:

        <common:ImageViewer x:Name="ctrlImage" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
            <common:ImageViewer.DataContext>
                <MultiBinding Converter="StaticResource ConverterWhichIsOnlyCalledOneWay" Mode="TwoWay" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged">
                    <Binding Path="." UpdateSourceTrigger="PropertyChanged" Mode="TwoWay" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True"/>
                </MultiBinding>
            </common:ImageViewer.DataContext>
        </common:ImageViewer>

我怎样才能调用ConvertBack

编辑:

我对控件和转换器进行了概述。我想我错了,应该调用 ConvertBack,一切都在更新,即使没有大转换器。但是在向ObservableCollection 添加一些元素时,我仍然卡住了。当我添加一些值时,这些值出现在 MainWindow 的 DataContext 中。但是转换器没有被触发。当我将 Observable.Count 作为绑定添加到 Big Converter 时,会触发更新,但所有绑定都会丢失。

对原始代码的更改是:将所有内部变量更改为 DependencyProperties,这使得 ObservableCollection 中的单个条目的更新可靠。

Overview of the GUI and the used converters

【问题讨论】:

在哪里更改画布的左上角或矩形宽度和高度属性? 画布左右保存在 ViewModel 中,在 ROI.Begin.PosH 和 .PosV 中。宽度是在 DegreeToScreenPixelHeightConverter 或 ..Width... 转换器上计算的,这完美无缺。更新也反映在 ListBox 的 SourceUpdate 中。 ConvertBack 仅在绑定值被视图模型外部的绑定控件以某种方式修改时才调用,对吗?除了视图模型之外,画布宽度和顶部值何时更改? 画布大小只在控件内部使用,从不向外传递。视图模型中只使用了 ROI.[Begin|End].[PosH|PosV],尽管它从视图模型中获取坐标系的信息(只是线性的) 那么,您希望何时以及为什么会调用 convertback?你的问题不清楚。 【参考方案1】:

是时候自己回答问题了:

当两个元素之间存在直接连接时,假设更改通过转换器向下传播,我错了。

因此,如果我有一个嵌套很深的元素(只需将其视为树的叶子),并且它曾经通过转换器显示一次(它会更改 一些 其他对象)并且相同在没有转换器的情况下,元素会在不调用转换器的情况下更新。 WPF 非常聪明地看到值是相同的,并且不会通过转换器上下管道更改。

【讨论】:

以上是关于未调用 ConvertBack的主要内容,如果未能解决你的问题,请参考以下文章

numberOfRowsInSection 已调用但 cellForRowAt 未调用

调用 textFieldShouldBeginEditing,未调用 textFieldDidBeginEditing

JQuery:未捕获的类型错误:无法读取未定义的属性“调用”

调用结果未使用

C# Web Api 调用未从 jquery 调用

未调用 cellForRowAtIndexPath 但调用 numberOfRowsInSection