2

我们在 WPF 应用程序中使用自定义弹出窗口。WPF 本机弹出窗口的问题在于:

  • 它使用新的 Windown,因此内容最终会出现在另一个可视化树中,这使得变换计算更加复杂,并且您无法控制 Zindex。它总是在其余部分之上。
  • 内容松散了 DataContext 和所有继承的属性或资源。

我们的自定义弹出窗口与原生 WPF 弹出窗口的不同之处在于,它将弹出窗口的内容放在同一个窗口的容器中,而不是放在新窗口中。内容是弹出窗口的逻辑子级。因此,它通过 DataContext 和 DP 继承解决了本机弹出问题。

我们的 Popup 像 XAML 中的原生一样工作

<pop:UbiPopup IsOpen="{Binding ElementName=pop_button,Path=IsChecked,Mode=TwoWay}" PlacementTarget="{Binding ElementName=maingrid}" Placement="CenterHorizontal,Top" >
    <Border Background="Blue" BorderThickness="0"  Margin="5">
           <TextBlock Text="{Binding Label}"
    </Border>
 </pop:UbiPopup>

但是绑定有一个错误。在弹出窗口的内容中完成绑定时,绑定将不起作用。但是如果我们使用 Snoop ( https://github.com/snoopwpf/snoopwpf ) 并检查对象,Binding 会突然起作用。它使用 datacontext 或 elementname 对每种类型的绑定执行此操作。

在内部,当 snoop 显示对象的 DP 列表时,如果由于某种原因找到绑定,则将其删除并重新放回。所以我们想出了这个相当丑陋的黑客来使绑定工作。加载弹出内容时,我们遍历所有可视子项,通过反射获取其所有 DP,如果它有绑定,我们将其删除并重新放回

警告:丑陋的代码

//Binding don't work inside UbiPopup. They work if they are snooped.
//So we simulate Snoop. we check every DP of every visual children of the Popup and we re-set the Binding if one is found.
foreach (var obj in WpfHelper.ChildrenEnumerator(container))
{
    var props = obj.GetType().GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.FlattenHierarchy)
    .Where((f) => f.FieldType.Equals(typeof(DependencyProperty)))
    .Select((f) => f.GetValue(null) as DependencyProperty);
    foreach (var p in props)
    {
        var bd = BindingOperations.GetBindingBase(obj, p);
        if (bd != null)
        {
            BindingOperations.SetBinding(obj, p, bd);
        }
    }
}

有谁知道这个问题可能来自哪里以及如何以更清洁的方式解决它

4

1 回答 1

0

Snoop 不会删除和重新应用绑定。它所做的是创建新的绑定,这些绑定绑定到对象/控件的 DependencyProperties,这会导致您的绑定再次被评估。

您写道您正在将内容添加到逻辑树中,如果您通过调用 AddLogicalChild 执行此操作,您还应该覆盖 LogicalChildren 属性以返回内容。

希望能解决您的问题。

于 2020-03-30T17:35:40.797 回答