1
votes

I have two radio buttons (RadioButton1 and RadioButton2). I need to display appropriate popup message when mouse is over one of the radio button. Hence I have following requirements

  • Requirement 1: When mouse is over "Radio Button 1" pop up message should be "Radio Button 1 is clicked". Similarly when mouse is over "Radio Button 2" pop up message should be "Radio Button 2 is clicked" .

  • Requirement 2: When mouse is clicked outside pop up control, pop up should close.

  • Requirement 3: Pop up also has hyperlink that displays a webpage when clicked. for this reason it should stay open.

To fulfill above requirements, i have used WPF pop up control with following settings

<Popup IsOpen="{Binding IsPopupOpen, Mode=TwoWay}" AllowsTransparency="True" PopupAnimation="Slide" StaysOpen="False" Placement="Bottom"  >
  <TextBlock  Text="{Binding RadioButtonContent, Mode=OneWay}" />

IsPopupOpen & RadioButtonContent are MVVM ViewModel properties that are updated when "MouseEnter" (used interaction trigger)event happens on one of radio button.

However i have encountered following issue.

When moving mouse from Radio Button 1 (at this time pop up is opened to Radio Button2, Pop up does not show "Radio Button 2 is clicked". It still shows "Radio Button 1 is clicked "!!!.

After reading the documentation for Popup in MSDN, i found the this is the correct behaviour, since whenever pop is opened, Mouse capture is with pop up content (TextBlock in this case). Hence "MouseEnter" event for RadioButton2 is not fired, even though mouse is over Radiobutton 2.

Note: I cannot make StaysOpen="True" since it will not close clicking outside pop up parent. (Requirement 2 fails) I cannot use controls like "Tooltip" or "adorner" since it wont stay. (requirement 3 fails)

How can i satisfy all 3 requirements?

1
You have to use the Popup and add a TextBlock which contains a Hyperlink as its child element. Then use an EventTrigger that triggers on RadioButton.MouseEnter and animate the Popup.IsOpen property to show the Popup.BionicCode
Hi BionicCode, Thank you. I did those things. But my requirement is when i move my mouse from Radio button 1 to radio button 2, i should get pop up for radio button 2. This does not happen because when mouse is over Radio button 1, pop up content is displayed as "radio Button 1 is clicked". Pop up stays open and has mouse capture. So when mouse is over "radio button 2" mouse enter for radio button is not triggered (since mouse capture is still with pop content !!!)Gajanana
If you could include a picture or two and probably some XAML code that would be helpfulKeith Stein
<Popup IsOpen="{Binding IsPopupOpen, Mode=TwoWay}" AllowsTransparency="True" PopupAnimation="Slide" StaysOpen="False" Placement="Bottom" > <TextBlock Text="{Binding RadioButtonContent, Mode=OneWay}" /> </Popup> IsPopupOpen & RadioButtonContent are MVVM ViewModel properties that are updated when "MouseEnter" (used interaction trigger)event happens on one of radio button.Gajanana
So, create two Popup elements (one for each RadioButton). On RadioButton.MouseEnter always close the other popup(s) by animating Popup.IsOpen to False. During the same animation timeline show the current Popup. This way they will behave mutual exclusive.BionicCode

1 Answers

2
votes

The key is to set the Popup.StaysOpen property to True (which is the default value). Now that the Popup doesn't close automatically, you have to do it manually. To implement the default behavior (Popup closes when clicked somewhere in the window), you should add the required EventTrigger and handle e.g., FrameworkElement.PreviewMouseUp on Window level (or the appropriate focus scope).

The following example shows a Popup when the RadioButton raises the FrameworkElement.MouseEnter event. Each RadioButton has a dedicated Popup. Before this Popup displays, all other Popup tool tips are closed. Once the Popup or any other control (regarding the scope of the EventTrigger) raises the FrameworkElement.PreviewMouseUp event, the opened Popup will be closed. With this configuration the Popup is allowed to receive only a single click (e.g. Button).
To allow the Popup to stay open if a child element received a mouse click, you could handle Popup.PreviewMouseUp events with a dedicated EventTrigger which sets Popup.IsOpen to True (to override the Popup close EventTrigger). For a more complex behavior I recommend to implement an Attached Behavior.

<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        x:Name="Window"
        Width="800"
        Height="600">

  <StackPanel>
    <Popup x:Name="ToolTip1"
           StaysOpen="True"
           PlacementTarget="{Binding ElementName=RadioButton1}">
      <Border Background="Transparent">
        <StackPanel>
          <TextBlock Text="Click to navigate to external content1" />
          <Button Content="Link" 
                  Command="{Binding NavigateToUrlCommand}"
                  CommandParameter="https://stackoverflow.com" />
        </StackPanel>
      </Border>
    </Popup>
    <Popup x:Name="ToolTip2"
           StaysOpen="True"
           PlacementTarget="{Binding ElementName=RadioButton2}">
      <Border Background="Transparent">
        <StackPanel>
          <TextBlock Text="Click to navigate to external content2" />
          <Button Content="Link" 
                  Command="{Binding NavigateToUrlCommand}"
                  CommandParameter="https://stackoverflow.com" />
        </StackPanel>
      </Border>
    </Popup>
    <RadioButton x:Name="RadioButton1" />
    <RadioButton x:Name="RadioButton2" />
  </StackPanel>

  <Window.Triggers>
    <EventTrigger SourceName="Window"
                  RoutedEvent="FrameworkElement.PreviewMouseUp">
      <BeginStoryboard>
        <Storyboard>
          <BooleanAnimationUsingKeyFrames Storyboard.TargetName="ToolTip1"
                                          Storyboard.TargetProperty="IsOpen">
            <DiscreteBooleanKeyFrame KeyTime="0:0:0"
                                     Value="False" />
          </BooleanAnimationUsingKeyFrames>
          <BooleanAnimationUsingKeyFrames Storyboard.TargetName="ToolTip2"
                                          Storyboard.TargetProperty="IsOpen">
            <DiscreteBooleanKeyFrame KeyTime="0:0:0"
                                     Value="False" />
          </BooleanAnimationUsingKeyFrames>
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>

    <EventTrigger SourceName="RadioButton1"
                  RoutedEvent="FrameworkElement.MouseEnter">
      <BeginStoryboard>
        <Storyboard>
          <BooleanAnimationUsingKeyFrames Storyboard.TargetName="ToolTip1"
                                          Storyboard.TargetProperty="IsOpen">
            <DiscreteBooleanKeyFrame KeyTime="0:0:0"
                                     Value="True" />
          </BooleanAnimationUsingKeyFrames>
          <BooleanAnimationUsingKeyFrames Storyboard.TargetName="ToolTip2"
                                          Storyboard.TargetProperty="IsOpen">
            <DiscreteBooleanKeyFrame KeyTime="0:0:0"
                                     Value="False" />
          </BooleanAnimationUsingKeyFrames>
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
    <EventTrigger SourceName="RadioButton2"
                  RoutedEvent="FrameworkElement.MouseEnter">
      <BeginStoryboard>
        <Storyboard>
          <BooleanAnimationUsingKeyFrames Storyboard.TargetName="ToolTip2"
                                          Storyboard.TargetProperty="IsOpen">
            <DiscreteBooleanKeyFrame KeyTime="0:0:0"
                                     Value="True" />
          </BooleanAnimationUsingKeyFrames>
          <BooleanAnimationUsingKeyFrames Storyboard.TargetName="ToolTip1"
                                          Storyboard.TargetProperty="IsOpen">
            <DiscreteBooleanKeyFrame KeyTime="0:0:0"
                                     Value="False" />
          </BooleanAnimationUsingKeyFrames>
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Window.Triggers>
</Window>