6

I have a DataGridTemplateColumn with DataTemplate as a PasswordBox.

I want to warn user if CapsLock is toggled.

private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
    {
        if (Keyboard.GetKeyStates(Key.CapsLock) == KeyStates.Toggled)
        {  
         ...

Now, I need to raise some PopUp here. I don't know how to do this. Help me please.

I tried to play around with ToolTip like this:

((PasswordBox)sender).SetValue(ToolTipService.InitialShowDelayProperty, 1);
((PasswordBox)sender).ToolTip = "CAPS LOCK";

But it works only when mouse cursor hovers there and I need an independent Popup.

H.B.
  • 166,899
  • 29
  • 327
  • 400
iLemming
  • 34,477
  • 60
  • 195
  • 309
  • @plotnick, commenting on your question rather than my answer so you don't miss it, can you set the tooltip to null on the LostFocus event of the PasswordBox (maybe setting IsOpen to false beforehand)? (I don't have WPF on my machine to test) – Patrick McDonald Jul 09 '09 at 09:14

5 Answers5

17

You could show a ToolTip

private void PasswordBox_KeyDown(object sender, KeyEventArgs e)
{
    if ((Keyboard.GetKeyStates(Key.CapsLock) & KeyStates.Toggled) == KeyStates.Toggled)
    {
        if (PasswordBox.ToolTip == null)
        {
            ToolTip tt = new ToolTip();
            tt.Content = "Warning: CapsLock is on";
            tt.PlacementTarget = sender as UIElement;
            tt.Placement = PlacementMode.Bottom;
            PasswordBox.ToolTip = tt;
            tt.IsOpen = true;
        }
    }
    else
    {
        var currentToolTip = PasswordBox.ToolTip as ToolTip;
        if (currentToolTip != null)
        {
            currentToolTip.IsOpen = false;
        }

        PasswordBox.ToolTip = null;
    }
}
Patrick McDonald
  • 64,141
  • 14
  • 108
  • 120
  • Oh... it seems this one goes for me, but it still opens the ToolTip at the mouse cursor. I need a ToolTip right under the PasswordBox – iLemming Jul 07 '09 at 15:07
  • tt.Placement = PlacementMode.Custom; Now it's under the PasswordBox – iLemming Jul 07 '09 at 15:20
  • Patrick... I have another problem. ToolTip doesn't go anywhere. Even if PasswordBox loses control. How to force it to fade-off? I've tried to kill it in LostFocus event, but that thing you showed me gives birth every time to new ToolTip... – iLemming Jul 07 '09 at 16:01
  • 2
    In my case I needed to add a single line of code to get it to work properly: tt.PlacementTarget = sender as UIElement; I also set the Placement to Bottom to get it to appear just below the textbox. I hope this helps someone :-) – Hannish Jul 20 '15 at 10:12
7

My solution is a little bit different. I made a ContentControl you can put anything inside of, and it will notify the caps lock status. Add this class to your code.

  public sealed class ShowCapLock : ContentControl
  {
    public bool ShowMessage
    {
      get { return (bool)GetValue(ShowMessageProperty); }
      set { SetValue(ShowMessageProperty, value); }
    }
    public static readonly DependencyProperty ShowMessageProperty =
        DependencyProperty.Register("ShowMessage", typeof(bool), typeof(ShowCapLock), new PropertyMetadata(false));

    static ShowCapLock()
    {
      DefaultStyleKeyProperty.OverrideMetadata(typeof(ShowCapLock), new FrameworkPropertyMetadata(typeof(ShowCapLock)));
    }

    public ShowCapLock()
    {
      IsKeyboardFocusWithinChanged += (s,e) => RecomputeShowMessage();
      PreviewKeyDown += (s,e)=> RecomputeShowMessage();
      PreviewKeyUp += (s,e)=> RecomputeShowMessage();
    }

    private void RecomputeShowMessage()
    {
      ShowMessage = IsKeyboardFocusWithin && System.Console.CapsLock;
    }
  }

And add some XAML to your generic.xaml

<Style TargetType="{x:Type controls1:ShowCapLock}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type controls1:ShowCapLock}">
                <Grid>
                    <ContentPresenter Name="Presenter"/>
                    <Popup Placement="Bottom" PlacementTarget="{Binding ElementName=Presenter}" 
                           IsOpen="{TemplateBinding ShowMessage}">
                        <Border Background="LightGoldenrodYellow" BorderThickness="1" BorderBrush="Black">
                            <TextBlock Foreground="Black">
                                <TextBlock>Caps Lock is down.</TextBlock>
                            </TextBlock>
                        </Border>
                    </Popup>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

And you can put a little control around anything you want to notify for caps lock:

            <controls:ShowCapLock Grid.Row="5" Grid.Column="1">
                <PasswordBox  . . ./>
            </controls:ShowCapLock>
John Melville
  • 3,613
  • 28
  • 30
7

I have made warning balloon to solve Caps Lock warning problem in my WPF-Project.

enter image description here

If you want to add this balloon warning in your project then follow these steps:

- Add new Window in your project and give name "WarningBalloon".
- Add following XAML code against new Window and add warning icon to image folder of project.

<Window x:Class="MyNameSpace.WarningBalloon"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Height="160" Width="469" WindowStyle="None" ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True" IsTabStop="False" OverridesDefaultStyle="False" AllowsTransparency="True" Background="Transparent" Opacity="1" >
        <Grid Height="126" Width="453">
            <Grid.RowDefinitions>
                <RowDefinition Height="81" />
                <RowDefinition Height="45*" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="177*" />
                <ColumnDefinition Width="72*" />
                <ColumnDefinition Width="0*" />
                <ColumnDefinition Width="170*" />
            </Grid.ColumnDefinitions>
            <Border Margin="12,32,0,0"
          CornerRadius="10,10,10,10" Grid.ColumnSpan="4" HorizontalAlignment="Left" Width="429" Height="82" VerticalAlignment="Top" Grid.RowSpan="2">
                <Border.Effect>
                    <DropShadowEffect
              Color="#FF474747" />
                </Border.Effect>
                <Border.Background>
                    <LinearGradientBrush
              EndPoint="0.5,1"
              StartPoint="0.5,0">
                        <GradientStop
                Color="#FF58C2FF"
                Offset="0" />
                        <GradientStop
                Color="#FFFFFFFF"
                Offset="1" />
                    </LinearGradientBrush>
                </Border.Background>
                <Grid Height="76" Name="grid1" Width="441">
                    <Image Height="35" HorizontalAlignment="Left" Margin="6,6,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="35" Source="/MyNameSpace;component/Images/warning-icon.png" />
                    <Label Content="Caps Lock is ON" Height="31" HorizontalAlignment="Left" Margin="125,-6,0,0" Name="lblWarningHeader" VerticalAlignment="Top" FontSize="16" FontWeight="Bold" />
                    <TextBlock HorizontalAlignment="Right" Margin="0,22,17,-1" Name="txbMessage" Width="379">Having Caps Lock on may cause you to enter your password incorrectly. <LineBreak/> <LineBreak/> You should press Caps Lock to turn it of before entering your password. VerticalAlignment="Top" Width="346" FontSize="11"</TextBlock>
                </Grid>
            </Border>
            <Image
            Source="{Binding Path=IconSource}" Width="16" HorizontalAlignment="Left" Margin="-56,0,0,-38" Height="16" VerticalAlignment="Bottom" Grid.Row="1" />
            <Path Data="M10402.99154,55.5381L10.9919,0.64 0.7,54.9" Fill="LightSkyBlue" HorizontalAlignment="Left" Margin="32,3,0,0" Stretch="Fill" Stroke="Black" Width="22" Height="31" VerticalAlignment="Top" />
        </Grid>
    </Window>

- Type the following code behind the LoginForm.

    private Point location;
    public static  bool balloonVisFlag = false;
    private DispatcherTimer timer;
    WarningBalloon Balloon = null;

    private void ShowHideBalloon()
    {            
        if (System.Windows.Forms.Control.IsKeyLocked(System.Windows.Forms.Keys.CapsLock))
        {
            if (timer == null)
            {
                timer = new DispatcherTimer();
            }
            location = GetControlPosition(psbPassword);
            Balloon.Left = location.X;
            Balloon.Top = location.Y;
            Balloon.Show();
            balloonVisFlag = true;
            timer.Interval = TimeSpan.FromMilliseconds(5000);
            timer.IsEnabled = true;
            timer.Tick += new EventHandler(Timer_Tick);
            psbPassword.Focus();
        }
        else
        {
            Balloon.Hide();
            balloonVisFlag = false;
            psbPassword.Focus();
        }
    }

    Point GetControlPosition(Control myControl)
    {
        Point locationToScreen = myControl.PointToScreen(new Point(0, 0));
        PresentationSource source = PresentationSource.FromVisual(myControl);
        return source.CompositionTarget.TransformFromDevice.Transform(locationToScreen);
    }     

    private void psbPassword_KeyDown(object sender, KeyEventArgs e)
    {
        ShowHideBalloon();
    }

    private void Window_LocationChanged(object sender, EventArgs e)
    {
        if (balloonVisFlag == true)
        {
            ShowHideBalloon();
        }
    }

    private void Timer_Tick(object sender, EventArgs e)
    {
        if (balloonVisFlag == true)
        {
            Balloon.Hide();
            balloonVisFlag = false;
        }
    }    
}
NASSER
  • 5,900
  • 7
  • 38
  • 57
0

It completely depends on your architecture, but for a simple solution:

You should be setting a Dependency Property, which will be observed by some sort of control on the Window that will become visible and will display the warning for the user.

Chris Nicol
  • 10,256
  • 7
  • 39
  • 49
0

Hi I worked on john's solution and I've wrote this example:

I used the same class ShowCapLock.

just to do the vector image I've used the Blend , so also for the upper box cusp segment.

And this is xaml code:

xmlns:options="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
xmlns:Controls="clr-namespace:[insertHereYourControlNamespace]"

<Color x:Key="LukeBlu" A="#FF" R="#11" G="#80" B="#B4" x:Shared="false"/>
<Color x:Key="LukeBlu1" A="#FF" R="#D1" G="#E4" B="#F7" x:Shared="false"/>
<SolidColorBrush x:Key="LukeBluBrush" Color="{DynamicResource LukeBlu}" x:Shared="false" options:Freeze="True" />

 <LinearGradientBrush x:Key="LukeBackgroundScreenBox" EndPoint="0.5,1" StartPoint="0.5,0">
    <GradientStop Color="{StaticResource LukeBlu1}" Offset="0"/>
    <GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>

<VisualBrush x:Key="Warning2" x:Shared="false" Stretch="Uniform" options:Freeze="True">
    <VisualBrush.Visual>
        <Canvas>
            <Path Data="F1M182.484,91.242C182.484,141.633 141.633,182.484 91.242,182.484 40.851,182.484 0,141.633 0,91.242 0,40.851 40.851,0 91.242,0 141.633,0 182.484,40.851 182.484,91.242z" Fill="White" Height="182.484" Canvas.Left="4.758" Canvas.Top="4.758" Width="182.484"/>
            <Path Data="M67.149,0C55.661,17.441 -5.077,100.609 0.341,114.844 21.571,115.828 123.934,126.996 133.954,114.844 124.36,96.117 82.434,2.484 67.149,0z M67.204,33.039C69.282,33.039,70.954,34.715,70.954,36.793L70.954,70.281C70.954,72.359 69.282,74.031 67.204,74.031 65.126,74.031 63.454,72.359 63.454,70.281L63.454,36.793C63.454,34.715,65.126,33.039,67.204,33.039z M67.204,94.336C69.126,94.336 70.684,95.898 70.684,97.82 70.684,99.746 69.126,101.305 67.204,101.305 65.282,101.305 63.724,99.746 63.724,97.82 63.724,95.898 65.282,94.336 67.204,94.336z" Fill="#FFFFA81C" Height="120.47" Canvas.Left="28.796" Canvas.Top="23.25" Width="133.954"/>
            <Path Data="F1M137.76,107.196L78.998,5.414C77.041,2.024 73.533,0 69.615,0 65.697,0 62.189,2.024 60.232,5.414L1.47,107.196C-0.49,110.586 -0.49,114.637 1.47,118.032 3.428,121.422 6.935,123.446 10.853,123.446L128.377,123.446C132.295,123.446 135.803,121.422 137.76,118.032 139.72,114.637 139.72,110.586 137.76,107.196z M131.865,114.625C131.513,115.231,130.474,116.641,128.377,116.641L10.853,116.641C8.756,116.641 7.713,115.231 7.365,114.625 7.017,114.02 6.314,112.414 7.365,110.598L66.127,8.821C67.178,7.004 68.916,6.805 69.615,6.805 70.314,6.805 72.053,7.004 73.103,8.821L131.865,110.598C132.916,112.414,132.213,114.02,131.865,114.625z" Fill="#FF231F20" Height="123.446" Canvas.Left="26.385" Canvas.Top="20.777" Width="139.23"/>
            <Path Data="F1M10.383,0C4.66,0,0,4.656,0,10.383L0,44.082C0,49.804 4.66,54.461 10.383,54.461 16.106,54.461 20.766,49.804 20.766,44.082L20.766,10.383C20.766,4.656,16.106,0,10.383,0z M13.957,44.082C13.957,46.051 12.352,47.656 10.383,47.656 8.41,47.656 6.809,46.051 6.809,44.082L6.809,10.383C6.809,8.41 8.41,6.808 10.383,6.808 12.352,6.808 13.957,8.41 13.957,10.383z" Fill="#FF231F20" Height="54.461" Canvas.Left="85.617" Canvas.Top="49.512" Width="20.766"/>
            <Path Data="F1M10.211,0C4.582,0 0,4.582 0,10.211 0,15.844 4.582,20.422 10.211,20.422 15.84,20.422 20.422,15.844 20.422,10.211 20.422,4.582 15.84,0 10.211,0z M10.211,13.617C8.332,13.617 6.809,12.09 6.809,10.211 6.809,8.336 8.332,6.809 10.211,6.809 12.086,6.809 13.613,8.336 13.613,10.211 13.613,12.09 12.086,13.617 10.211,13.617z" Fill="#FF231F20" Height="20.422" Canvas.Left="85.789" Canvas.Top="110.781" Width="20.422"/>
            <Path Data="M187.241,95.999C187.241,146.39 146.39,187.241 95.999,187.241 45.608,187.241 4.757,146.39 4.757,95.999 4.757,45.608 45.608,4.757 95.999,4.757 146.39,4.757 187.241,45.608 187.241,95.999z" Height="191.997" Canvas.Left="0.001" Stroke="#FF090909" StrokeThickness="9.513" StrokeLineJoin="Round" Canvas.Top="0.001" Width="191.997"/>
        </Canvas>
    </VisualBrush.Visual>
</VisualBrush>

<!--#region Caps lock message warning -->
<Style TargetType="{x:Type Controls:ShowCapLock}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Controls:ShowCapLock}">
                <Grid>
                    <ContentPresenter Name="Presenter"/>
                    
                    <Popup Placement="Bottom" 
                           PlacementTarget="{Binding ElementName=Presenter}"
                           OverridesDefaultStyle="False" 
                           AllowsTransparency="True" 
                           Opacity="1" 
                           IsOpen="{TemplateBinding ShowMessage}" 
                           PopupAnimation="Fade">
                        
                        <Grid>                         
                            <Border Margin="12,32,0,0"                                      
                                    CornerRadius="10"
                                    BorderBrush="{StaticResource LukeBluBrush}"
                                    BorderThickness="3"
                                    Background="{DynamicResource LukeBackgroundScreenBox}"
                                    Padding="0">

                                <Grid Name="grid1">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="32*"/>
                                        <RowDefinition Height="0.5*"/>
                                        <RowDefinition Height="0.5*"/>
                                    </Grid.RowDefinitions>                                        
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="32*" MaxWidth="48"/>
                                        <ColumnDefinition Width="0.3*"/>
                                        <ColumnDefinition Width="0.8*"/>
                                        <ColumnDefinition Width="0.3*"/>
                                    </Grid.ColumnDefinitions>
                                
                                    <Rectangle Name="image1"
                                               Height="32"
                                               Width="32"
                                               Margin="3"
                                               Fill="{StaticResource Warning2}"/>

                                    <TextBlock Name="lblWarningHeader"
                                               Grid.Column="1" Grid.ColumnSpan="3"
                                               Margin="0,3"
                                               Text="Caps Lock is On" 
                                               VerticalAlignment="Center"
                                               HorizontalAlignment="Left"
                                               FontSize="16"
                                               FontWeight="Bold"/>
                                    
                                    <TextBlock Name="txbMessage" 
                                               Grid.Row="2" Grid.ColumnSpan="4"
                                               Margin="3"
                                               Text="Having Caps Lock on may cause you to enter your password incorrectly.\\r\\nYou should press Caps Lock to turn it of before entering your password."
                                            HorizontalAlignment="Right"/>
                                </Grid>
                            </Border>
                            <Path Data="M23,37L1,0.7 0.7,37"
                                  Stroke="{StaticResource LukeBluBrush}"
                                  StrokeThickness="3"
                                  HorizontalAlignment="Left"                                       
                                  Stretch="Fill" 
                                  Width="23" 
                                  Height="33.6"
                                  Margin="33,3,0,0"
                                  VerticalAlignment="Top">
                                <Path.Fill>
                                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                        <GradientStop Color="White" Offset="0"/>
                                        <GradientStop Color="{StaticResource LukeBlu1}" Offset="1"/>
                                    </LinearGradientBrush>
                                </Path.Fill>
                            </Path>                               
                        </Grid>
                    </Popup>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<!--#endregion-->

and to use it in your xaml code everywhere you want in this way:

<Controls:ShowCapLock >
          <PasswordBox x:Name="PasswordBox"
                       BorderBrush="{DynamicResource keBluBrush}"/>
</btbControls:ShowCapLock>
luka
  • 605
  • 8
  • 15