views:

1898

answers:

2

I have a TextBox and a Popup control. I want the popup IsOpen property to be bound to the TextBox IsFocused property. In other words, if the textbox has focus, the popup is open. Alternatively, if the popup is in focus, I don't want it to close due to the textbox losing focus. I was hoping to handle this using bindings rather than having to deal with this in event handlers. Also, do I have to do anything regarding the dependency properties, since they are pre-existing(i.e. Register, override metadata, etc), or can I just bind to these properties.

Here is some sample code similar to my scenario

StackPanel sp = new StackPanel();
TextBox tb = new TextBox();
Popup popup = new Popup();

sp.Children.Add(tb);
sp.Children.Add(popup);
this.Content = sp;

Binding bd = new Binding("IsFocused");
bd.source = tb.IsFocused;
popup.SetBinding(Popup.IsOpenProperty, bd);

From this I was assuming that if I clicked on the textbox control and gave it focus, that the popup would open, and conversely if the textbox lost focus, that the popup would close. I can't seem to get this to work.

If someone has an idea of what I'm doing wrong, then maybe they could also answer the second half of my question that if the textbox loses focus but it was the popup that receives focus, that the popup will remain open or give focus back to the textbox so that it will remain open bc of the first binding. Any other control that gains focus when the textbox loses focus does not apply to this scenario.

If I could reword this for clarity I would say it like this. 1.) Bind Popup.IsOpen to TextBox.IsFocused 2.) Bind TextBox.IsFocused to Popup.IsFocused(assuming this will just give focus back to the textbox)

+2  A: 

The following code demonstrates having two text boxes in a StackPanel, setting focus to the top text box will open the Popup. At which point, if you then move Focus to the text box contained in the Popup it will remain open. If you move focus to another element, in this instance the second text box in the StackPanel, the Popup will close. As you unable to focus the Popup itself I am actually binding to the IsFocused property of the text box in the Popup.

<StackPanel>
    <TextBox x:Name="text" Text="This is a text box" />
    <TextBox Text="Another Text Box" />
    <Popup PlacementTarget="{Binding ElementName=text}">
        <Popup.Style>
            <Style TargetType="{x:Type Popup}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding ElementName=text, Path=IsFocused}" Value="True">
                        <Setter Property="IsOpen" Value="True" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding ElementName=popupText, Path=IsFocused}" Value="True">
                        <Setter Property="IsOpen" Value="True" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Popup.Style>
        <TextBox x:Name="popupText" Text="HELLO WORLD" />
    </Popup>
</StackPanel>

To achieve the same thing in C# you don't have to use the ElementName bindings as you already have the elements right at hand. I almost always use XAML to define my elements so I'm sure you could tidy this a bit.

var text1 = new TextBox { Name = "text", Text = "This is a text box" };
var text2 = new TextBox { Text = "Another Text Box" };
var popupText = new TextBox { Name = "popupText", Text = "HELLO WORLD" };
var popup = new Popup { Child = popupText, PlacementTarget = text1 };
var stackPanel = new StackPanel();

stackPanel.Children.Add(text1);
stackPanel.Children.Add(text2);
stackPanel.Children.Add(popup);

var popupStyle = new Style(typeof (Popup));
var textIsFocusedTrigger = new DataTrigger
    {
        Binding = new Binding {Source = text1, Path = new PropertyPath("IsFocused")},
        Value = true
    };

textIsFocusedTrigger.Setters.Add(new Setter(Popup.IsOpenProperty, true));

var popupTextIsFocusedTrigger = new DataTrigger
    {
        Binding = new Binding {Source = popupText, Path = new PropertyPath("IsFocused")},
        Value = true
    };

popupTextIsFocusedTrigger.Setters.Add(new Setter(Popup.IsOpenProperty, true));

popupStyle.Triggers.Add(textIsFocusedTrigger);
popupStyle.Triggers.Add(popupTextIsFocusedTrigger);

popup.Style = popupStyle;

I hope this helps!

David Padbury
This seems to be very close to what I'm wanting to do. I ran your code in a test application and the behavior is very similar. I have written the C# to do what your xaml is doing, but something is still off. Since I am not using XAML, I'm thinking I'm having trouble with binding to ElementName. Do have I have to just set the Name property or do register name. Below you will see what I have so far, let me know if you can see what might be wrong. Thanks a lot.
BrandonS
I've just edited my answer to provide a C# version of what I was doing in XAML, hopefully this is what you need. Out of interest, why are you using C# over XAML to create your elements?
David Padbury
A: 

Here is my first C# attempt at this. Something is still not quite right. Nothing happens so I'm not quite sure where my mistake is.

        StackPanel sp = new StackPanel(); 
        TextBox tb = new TextBox(); 
        Popup popup = new Popup();

        TextBox popupTextBox = new TextBox();
        popup.Child = popupTextBox;


        sp.Children.Add(tb); 
        sp.Children.Add(popup); 
        this.Content = sp;


        //***Questions concerning giving the UIElement a name and registering it
        tb.Name = "siblingTextBox";
        System.Windows.NameScope.GetNameScope(tb).RegisterName("siblingTextBox", tb);

        //***Questions concerning giving the UIElement a name and registering it
        popupTextBox.Name = "popupTextBox";
        System.Windows.NameScope.GetNameScope(tb).RegisterName("popupTextBox", popupTextBox);

        Binding binding = new Binding();
        binding.ElementName = tb.Name;
        popup.PlacementTarget = tb;

        Style style = new Style();
        style.TargetType = typeof(Popup);

        DataTrigger dataTrigger = new DataTrigger();
        Binding focusedBinding = new Binding("IsFocused");
        focusedBinding.ElementName = tb.Name;
        dataTrigger.Value = true;
        dataTrigger.Binding = focusedBinding;

        Setter setter = new Setter();
        setter.Property = Popup.IsOpenProperty;
        setter.Value = true;
        dataTrigger.Setters.Add(setter);
        style.Triggers.Add(dataTrigger);

        dataTrigger = new DataTrigger();
        focusedBinding = new Binding("IsFocused");
        focusedBinding.ElementName = popupTextBox.Name;
        dataTrigger.Value = true;
        dataTrigger.Binding = focusedBinding;
        setter = new Setter();
        setter.Property = Popup.IsOpenProperty;
        setter.Value = true;
        dataTrigger.Setters.Add(setter);
        style.Triggers.Add(dataTrigger);

        popup.Style = style;
BrandonS