Search code examples
c#wpfxamldependency-propertiesismouseover

Bind to or Expose IsMouseOver or any other ReadOnly DependencyProperty from element inside UserControl


I have a window with a UserControl, that UserControl has an element. If I move the mouse over the element inside the UserControl, I want that some other elements inside the Window to react (for example: hide them).

enter image description here

<Window x:Class="WpfApplication4.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525"
    xmlns:local="clr-namespace:WpfApplication4"
    >
<DockPanel>
    <Grid Width="50" Height="50" Background="Yellow">
        <Grid.Style>
            <Style TargetType="Grid">
                <Style.Triggers>

                    <!-- When hovering innerControl inside userControl  this grid should become invisible, of course this doesn't work, it hides the element if I move the mouse over any part of the usercontrol-->

                    <DataTrigger Binding="{Binding userControl.IsMouseOver, ElementName=userControl}" Value="True">
                        <Setter Property="Visibility" Value="Collapsed" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Grid.Style>
    </Grid>
    <local:userControl x:Name="userControl" Width="300" Height="300"/>
</DockPanel>

UserControl

<UserControl x:Class="WpfApplication4.userControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300"
         Background="Red"
         >
    <Grid>
    <Grid x:Name="innerControl" Background="Blue" Width="100" Height="100"/>
</Grid>

public partial class userControl : UserControl
{
    public userControl()
    {
        InitializeComponent();
    }

    //This is far from working

    public new bool  IsMouseOver
    {
        get { return (bool)GetValue(IsMouseOverProperty); }
        set { SetValue(IsMouseOverProperty, value); }
    }

    public new static readonly DependencyProperty IsMouseOverProperty =
        Border.IsMouseOverProperty.AddOwner(typeof(Border));
}

I know I have to use Dependency Properties, but I can't adapt the examples I have found to this problem.


Solution

  • Just in case anyone cares, here's the solution

    Adapted from this answer: https://stackoverflow.com/a/317699/3596441

    Expose child controls properties in UserControl:

    public partial class userControl : UserControl
    {
        public userControl()
        {
            InitializeComponent();
            DependencyPropertyDescriptor descriptor = DependencyPropertyDescriptor.FromProperty(FrameworkElement.IsMouseOverProperty, typeof(FrameworkElement));
            descriptor.AddValueChanged(this.innerControl, new EventHandler(OnIsMouseOverChanged));
    
        }
    
        // Dependency Property Declaration
        private static DependencyPropertyKey ElementIsMouseOverPropertyKey = DependencyProperty.RegisterReadOnly("ElementIsMouseOver", typeof(bool),typeof(userControl), new PropertyMetadata());
        public static DependencyProperty ElementIsMouseOverProperty = ElementIsMouseOverPropertyKey.DependencyProperty;
    
    
        public bool ElementIsMouseOver
        {
            get { return (bool)GetValue(ElementIsMouseOverProperty); }
        }
        private void SetIsMouseOver(bool value)
        {
            SetValue(ElementIsMouseOverPropertyKey, value);
        }
    
        // Dependency Property Callback
        // Called when this.MyElement.ActualWidth is changed
        private void OnIsMouseOverChanged(object sender, EventArgs e)
        {
            this.SetIsMouseOver(this.innerControl.IsMouseOver);
        }
    
    
    }
    

    Use like this:

    <Window x:Class="WpfApplication4.MainWindow"
      ...
        xmlns:local="clr-namespace:WpfApplication4"
        >
    <DockPanel>
        <Grid DockPanel.Dock="Left" Width="100" Height="100" Background="Yellow">
            <Grid.Style>
                <Style TargetType="Grid">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding ElementIsMouseOver, ElementName=userControl}" Value="True">
                            <Setter Property="Visibility" Value="Collapsed"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Grid.Style>
        </Grid>
    
        <local:userControl x:Name="userControl" Width="300" Height="300"/>
    
    </DockPanel>