0

I have a UserControl with a number of StackPanel's. I like to hide specific panels depending on the user action. A StackPanel which is visible on startup gives me a number of working buttons. The buttons have click events in the code behind file. After collapsing the panel and then making it visible again the buttons no longer work. Here is a part of my UserControl:

<StackPanel x:Name="buttonPanel" Orientation="Horizontal">
    <Button x:Name="ReMindNodeNotes" Content="&#xE104;"
            FontFamily="Segoe UI Symbol" FontSize="14" Foreground="#FF292323" 
            HorizontalAlignment="Left" BorderThickness="1" Padding="0"
            UseLayoutRounding="True" Click="NoteClicked" />
    <Button x:Name="ReMindNodeRemove" Content="&#xE107;"
            FontFamily="Segoe UI Symbol" FontSize="14" Foreground="#FF292323" 
            HorizontalAlignment="Left" BorderThickness="1" Padding="0"
            UseLayoutRounding="True" Click="RemoveClicked" />
</StackPanel>

And here is the code (for now just some text):

private void NoteClicked(object sender, RoutedEventArgs e)
{
    System.Diagnostics.Debug.WriteLine("NoteClicked...");
}

private void RemoveClicked(object sender, RoutedEventArgs e)
{
    System.Diagnostics.Debug.WriteLine("RemoveClicked...");
}

I have been looking for a solution the last two days. No luck so far. Who can help...?

THX Peter


Follow up 1...

Here is the code for collapsing the panel:

    private void MoreClicked(object sender, RoutedEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine(this.nodeName);
        this.buttonPanel.Visibility =
            this.buttonPanel.Visibility ==
                Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
    }

It works if the buttonPanel has focus. If the focus is on another panel it does not. Furthermore, what I probably should have mentioned... is that users can create multiple instances of the user control.

THX


Follow up 2...

I continue working on a solution of course... ;-) and I found a solution, which however is not the solution I want. Let me explain.

Users can interactively create multiple instances of the user control mentioned before. When a new instance is created, that instance gets focus. Now every instance has its own set of buttons which are on a stackpanel. When the focus goes to another instance I want the panel of the previous instance to collapse. The focus should then be set to the new (or selected existing) instance.

When I do this manually, it works! When I try to achieve this through the GotFocus and LostFocus events however, it does not. Here is the code for the manual solution (which works):

    private void MoreClicked(object sender, RoutedEventArgs e)
    {
        this.buttonPanel.Visibility = 
            this.buttonPanel.Visibility == 
                Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
    }

Here are the LostFocus and GotFocus events:

    private void NodeGotFocus(object sender, RoutedEventArgs e)
    {
        this.buttonPanel.Visibility = Visibility.Visible;
    }

    private void NodeLostFocus(object sender, RoutedEventArgs e)
    {
        this.buttonPanel.Visibility = Visibility.Collapsed;
    }

I really appreciate your help! THX again...

Brandon
  • 16,382
  • 12
  • 55
  • 88
Peter Schulz
  • 43
  • 1
  • 4
  • Behavior you are talking about is very strange. Could you share your code for collapsing the panel? – Oleg Ignatov May 23 '13 at 10:04
  • I added the code to the orignal post Oleg. Don't know how to add another post yet... ;-) – Peter Schulz May 23 '13 at 10:45
  • I've created a sample application with your code - and it works as expected - seems the problem is in how you use your control on page, not the event handlers themselves. BTW when you define a name in XAML, VS creates a corresponding field in code-behind, so you can do just this.buttonPanel.Visibility – morincer May 23 '13 at 14:01
  • Thanks for the tip morincer! I didn't know access panel and buttons can be accessed directly in the code behind. Can you send me your sample? That might be really helpful! – Peter Schulz May 23 '13 at 15:26
  • Sure. I've found no email in your profile so take it at https://www.dropbox.com/s/698t98lqybyciwi/Sample.zip – morincer May 23 '13 at 19:28
  • THX!!! I really appreciate that! ;-) I'm busy today but will have a look at your sample a.s.a.p. When I found the problem I'll write an update for other readers... – Peter Schulz May 24 '13 at 07:59

1 Answers1

0

Thanks for your sample morincer. The problem however is a little more complex. Let me try to explain the solution which I found after some more research. Maybe other developers can benefit from it as well.

I added the GotFocus and LostFocus events to my userconctrol. If I click somewhere inside the usercontrol the focus changes every time. Strange as these events are only defined on the usercontrol itself and not it's children. I have several buttons and a textbox inside the usercontrol and when I for example click on one of the buttons of the usercontrol that has focus the LostFocus and GotFocus events are fired for usercontrol anyway.

The most important event for me in this case is the LostFocus event. When the usercontrol looses focus - for example to another control - I want the button panel to disappear. Since the LostFocus event fires every time a object inside the usercontrol is touched, I cannot distinguish between the situation in which I want to hide and show the buttons.

I got a little closer to a solution by changing the LostFocus event as follows:

    private void LostFocus(object sender, RoutedEventArgs e)
    {
        Object fo = FocusManager.GetFocusedElement();
        if (fo.GetType().ToString().Contains("TextBox") ||
            fo.GetType().ToString().Contains("ScrollViewer"))
        {
            this.buttonPanel.Visibility = Visibility.Collapsed;
        }
    }

This covers most of the situations. When the cursor is positioned in the TextBox the button panel is closed. The button panel is also closed when the user clicks on the background. This seems to be a ScrollViewer (found through debugging the code). Can anyone explain this...?

The situation which is not covered however, is when a user clicks on another usercontrol. It does of course when the user clicks on the TextBox (see the code) but not when the user clicks on a button. I tried to compare sender and FocusManager.GetFocusedElement(). Problem is that the sender returns the usercontrol (which is what I am looking for) but the FocusManager.GetFocusedElement() returns the button that was pressed. Now I could ask for it's parent which is a border then ask for the borders parent which is a stack panel and so on until I arrive at the usercontrol. A code behind file however was introduced with the idea to split design and logic while this solution would tie them together again. If I would change the XAML I would have to change the logic as well. Doesn't seem to be the right solution to me.

I found a solotion by giving every usercontrol a unique name in the constructor. I then give all the buttons unique names as well (I don't use them in my code anyway) starting with the name of the usercontrol. This then gives me the possibility to compare names at runtime and determine whether the focus has changed to another instance of the usercontrol. Here is the code:

    private void NodeLostFocus(object sender, RoutedEventArgs e)
    {
        Object fo = FocusManager.GetFocusedElement();
        if (fo.GetType().ToString().Contains("ScrollViewer"))
        {
            this.buttonPanel.Visibility = Visibility.Collapsed;
        }
        else if (fo.GetType().ToString().Contains("TextBox"))
        {
            if (!((TextBox)fo).Name.Contains(this.nodeName))
            {
                this.buttonPanel.Visibility = Visibility.Collapsed;
            }
        }
        else if (fo.GetType().ToString().Contains("Button"))
        {
            if (!((Button)fo).Name.Contains(this.nodeName))
            {
                this.buttonPanel.Visibility = Visibility.Collapsed;
            }
        }
    }

Now this works! But…I don't like the solution. I am depending on names instead of a good architecture. Does anyone hove an idea how to compare the actual sender with the usercontrol that is the parent of the button pressed (FocusManager.GetFocusedElement())? Or any other solution that relies on good programming?

THX again

Peter Schulz
  • 43
  • 1
  • 4