locked
How to detect visibilty change state of UIelement from child element? RRS feed

  • Question

  • I have a child element that handles certain events, of which should be unhooked if a parent of its' visual tree is collapsed and re-hooked when the parent is made visible again.

    for example:

    Parent
      - Child1
      - Child2
        --child2.sub
      - Child3

    child2.sub UIelement (a user control, but could also be a template control), processes certain events, but may never have its' visibility changed directly.. rather Child2 or Parent may, so the child2.sub should unhook its' events (perhaps for another control to handle).

    How do I do this?

    I've tried LayoutUpdated, and it simply fires too frequently and while throwing a Boolean check in could help control hook/unhook calls.. it seems to be a waste of cycles when the hooks only need to be done periodically.


    • Edited by tsw Wednesday, October 23, 2013 3:15 AM
    Wednesday, October 23, 2013 3:14 AM

Answers

  • Here's a thought:  create a control that has a Boolean property.  Create it in XAML.  Bind the property to the visibility of the parent control via a converter.  When the converter fires, use that code to hook/unhook the events and return the value.  In essence, you're creating an event for the visibility property of the parent control. 

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    • Marked as answer by tsw Wednesday, October 23, 2013 10:21 PM
    Wednesday, October 23, 2013 12:43 PM
    Moderator

All replies

  • Here's a thought:  create a control that has a Boolean property.  Create it in XAML.  Bind the property to the visibility of the parent control via a converter.  When the converter fires, use that code to hook/unhook the events and return the value.  In essence, you're creating an event for the visibility property of the parent control. 

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    • Marked as answer by tsw Wednesday, October 23, 2013 10:21 PM
    Wednesday, October 23, 2013 12:43 PM
    Moderator
  • Thanks for idea Matt, this may be easier to implement than what I was considering... which was something along the Observer Design Pattern approach :)

    .. working on this, and will bump when answered.

    thanks again!

    Wednesday, October 23, 2013 8:35 PM
  • ok, I found out that IsEnabled is inherited on child controls.  For simplicity, I just set the IsEnabled to false when the parent element visibility is collapsed.  By creating a dependency property and callback of my choosing within my template control and binding that to its' own IsEnabled solves the problem.  I can now at least hook/unhook as needed.

    Unfortunately, when binding my dependency property this way: (IsActive is the dependency property with callback method)

    IsActive="{Binding IsEnabled, RelativeSource={RelativeSource Mode=Self}}"

    would create a really ugly error in Visual Studio Design View

     XamlParseException: Failed to assign to property 'App1.myControl.IsActive'. [Line: 16 Position: 98]

     The app would surprisingly run and work as intended, but that meant I had a huge red X in my editor.. not sure how to work around that.

    Since IsEnabled is.. well a Control dependency property, I just hooked to this in my template control (Child2.sub in the example), and handled it with a method that way.. nice and clean and no weird errors in the editor.

    would be nice to know though, why when I created my own dependency property that design view produced that ugly error.  Is there something in the PropertyMetadata that needs to be set or something in particular in the PropertyChangedCallback specifically for design time that needs to be handled that I wasn't?

    Wednesday, October 23, 2013 10:58 PM
  • here's a bit more detail on the error thrown in design view:

    Exception: Cannot create an instance of "myChild2Sub".
       at Microsoft.Expression.Platform.InstanceBuilders.InstanceBuilderOperations.InstantiateType(Type type, Boolean supportInternal)
       at Microsoft.Expression.Platform.InstanceBuilders.ClrObjectInstanceBuilder.InstantiateTargetType(IInstanceBuilderContext context, ViewNode viewNode)
       at Microsoft.Expression.Platform.InstanceBuilders.ClrObjectInstanceBuilder.Instantiate(IInstanceBuilderContext context, ViewNode viewNode)
       at Microsoft.Expression.WindowsXamlPlatform.InstanceBuilders.FrameworkElementInstanceBuilder.Instantiate(IInstanceBuilderContext context, ViewNode viewNode)
       at Microsoft.Expression.WindowsXamlPlatform.InstanceBuilders.UserControlInstanceBuilder.Instantiate(IInstanceBuilderContext context, ViewNode viewNode)
       at Microsoft.Expression.Platform.InstanceBuilders.ViewNodeManager.CreateInstance(IInstanceBuilder builder, ViewNode viewNode)

    TargetInvocationException: Exception has been thrown by the target of an invocation.

    stack trace:
       at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
       at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)

    XamlParseException: Failed to assign to property 'App1.myControl.IsActive'. [Line: 16 Position: 98]

       at Windows.UI.Xaml.Application.LoadComponent(Object component, Uri resourceLocator, ComponentResourceLocation componentResourceLocation)
       at App1.myControl.InitializeComponent()
       at App1.myControl..ctor()


    InnerException: None

    Wednesday, October 23, 2013 11:05 PM