views:

4670

answers:

4

I have a window which overrides a RadioButton's ControlTemplate to show a custom control inside of it. Inside the custom control, I have a button's visibility tied to IsMouseOver, which works correctly in showing the button only when the mouse is hovering over the control. However, when I click on the RadioButton, the Button disappears. After some debugging and reading, it seems that the RadioButton is capturing the Mouse on click, and this makes IsMouseOver for the UserControl false.

I tried binding the Button's visibility to FindAncestor {x:Type RadioButton} and it works, but it seems a bit fragile to me to have the UserControl depend on who is containing it. The code for the window and the User Control is below. Any suggestions?

<Window.Resources>
 <Style
  TargetType="{x:Type RadioButton}">
  <Setter
   Property="Template">
   <Setter.Value>
    <ControlTemplate
     TargetType="{x:Type RadioButton}">

     <WPFTest:TestUC></WPFTest:TestUC>

    </ControlTemplate>
   </Setter.Value>
  </Setter>
 </Style>

</Window.Resources>

<Border
 BorderBrush="Black"
 BorderThickness="2">
 <StackPanel>
  <RadioButton
   x:Name="OptionButton"
   Height="100"
   >

  </RadioButton>

  <TextBlock
   Text="{Binding ElementName=OptionButton, Path=IsMouseOver}" />
 </StackPanel>
</Border>

<UserControl.Resources>
 <BooleanToVisibilityConverter
  x:Key="BooleanToVisibilityConverter" />
</UserControl.Resources>

 <StackPanel>
 <TextBlock
  Text="SomeText" />
 <TextBlock
  Text="{Binding ElementName=_this, Path=IsMouseOver}" />

 <Button
  x:Name="_cancelTextBlock"
  Content="Cancel"
  Visibility="{Binding ElementName=_this, Path=IsMouseOver, Converter={StaticResource BooleanToVisibilityConverter}}">

 </Button>
</StackPanel>

+1  A: 

I seemed to have fixed the problem by setting a trigger in the control template, which binds to the RadioButton's IsMouseOver, and sets a custom DependencyProperty on the UserControl.

Something like:

     <WPFTest:TestUC x:Name="UC"></WPFTest:TestUC>

     <ControlTemplate.Triggers>
      <Trigger
       Property="IsMouseOver"
       Value="True">
       <Setter Property="ShowCancel" Value="True" TargetName="UC"/>
      </Trigger>
     </ControlTemplate.Triggers>
    </ControlTemplate>

I'm still confused as to why the Mouse Capture falsifies IsMouseOver on the UserControl child of the RadioButton however. Can anyone shed some light on this?

DavidN
A: 

Very interesting problem. I myself would like to know more of why the UserControl IsMouseOver changes to false when the TextBlock(s) in its visuals are mouse downed upon.

However, here is another way to solve it ... maybe you will like this approach better.

Instead of using RadioButton (since you are retemplating it) why don't you just use Control? (I think IsMouseOver is getting changed to false due to the fact that it is a Button derived control.)

Following is the xaml for the Window ...

<Window
    x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    Title="Window1"
    Width="300"
    Height="300"
>
    <Window.Resources>
        <Style TargetType="{x:Type Control}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Control}">
                        <local:UserControl1/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

    <Border BorderBrush="Black" BorderThickness="2">
        <StackPanel>
            <Control x:Name="OptionButton" Height="100"/>
            <TextBlock Text="{Binding ElementName=OptionButton, Path=IsMouseOver}"/>
        </StackPanel>
    </Border>
</Window>

EDIT:

I just wanted to add ... that if you're okay with the above approach ... then, the right thing to do is probably to just use the UserControl in the Window's visual tree versus retemplating a Control. So ... like this:

<Window
    x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    Title="Window1"
    Width="300"
    Height="300"
>
    <Border BorderBrush="Black" BorderThickness="2">
        <StackPanel>
            <local:UserControl1 x:Name="OptionButton" Height="100"/>
            <TextBlock Text="{Binding ElementName=OptionButton, Path=IsMouseOver}"/>
        </StackPanel>
    </Border>
</Window>
cplotts
+1  A: 

After the event is handled by the RadioButton , it is only set as handled but in reality it still bubbles up. So you just need to specify that you want to handle handled events too.

For that you need to look at handledEventsToo.

Unfortunately I don't think it can be set in xaml. only code.

sirrocco
A: 

Can you make you code and project available for download