2

We use a Custom Popup in our WPF application. The problem with the WPF native popup is that:

  • It use a new Windown so the content end up in an other visual tree which make transform calculation more complicated and you have no control over the Zindex. it will always be on top of the rest.
  • The content loose the DataContext and all the Inherited properties or resources.

The difference of our custom popup with the native WPF Popup is that it put the Content of the popup is put in a container in the same window instead of putting it in a new windows. And the content is a logical child of the popup. So it solve the native popup problems with DataContext and DP inheritance.

Our Popup work like the native one in 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>

But there is a bug with Bindings. When a Binding is done in the Content of the Popup, the binding will not work. But if we use Snoop (https://github.com/snoopwpf/snoopwpf) and check the object, the Binding sudenly work. It does this for every kind of binding, using datacontext or elementname.

Internaly, when snoop display the list of DP of an objet, if it find a binding for some reason it remove it and put it back again. So we come up with this rather ugly hack to make bindings work. When the popup content is loaded, we walk along all visual child, get all their DP by reflection, and if it has a binding, we remove it and put it back again

Warning : Ugly Code

//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);
        }
    }
}

Does anyone know where this problem can com from and how to solve it in a cleaner way

Pekka
  • 3,529
  • 27
  • 45
Gael
  • 416
  • 1
  • 5
  • 16

1 Answers1

0

Snoop does not remove and re-apply bindings. What it does is create new bindings which bind to the DependencyProperties of the objects/controls which causes your bindings to be evaluated again.

You wrote that you are adding the content to the logical tree, if you do that by calling AddLogicalChild you should also overwrite the LogicalChildren property to return the content.

Hope that solves your issue.

batzen
  • 161
  • 2
  • 4