Changing the Cursor in Wpf Sometimes Works, Sometimes Doesn'T

Changing the cursor in WPF sometimes works, sometimes doesn't

Do you need the cursor to be a "wait" cursor only when it's over that particular page/usercontrol? If not, I'd suggest using Mouse.OverrideCursor:

Mouse.OverrideCursor = Cursors.Wait;
try
{
// do stuff
}
finally
{
Mouse.OverrideCursor = null;
}

This overrides the cursor for your application rather than just for a part of its UI, so the problem you're describing goes away.

WPF datagrid cursor doesn't change on column resize

Did you try to copy your first XAML snippet into a blank WPF project? Can you reproduce the issue then? I doubt it because I cannot.

As for your second snippet, you should either remove the ScrollViewer or move it to another row by adding another RowDefinition to the Grid and increase the value of Grid.Row attached property. Currently, it lays on top of the DataGrid.

Try this:

<Window ...>
<Grid x:Name="grid_main" Height="Auto" Width="Auto" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

<DataGrid x:Name="dg" Grid.Row="1">
<DataGrid.Columns>
<DataGridTextColumn Header="Test1" Width="100"/>
<DataGridTextColumn Header="Test2" Width="100"/>
<DataGridTextColumn Header="Test3" Width="100"/>
</DataGrid.Columns>
</DataGrid>

<DockPanel Width="Auto" Height="Auto">
<Button x:Name="btn_loadSchema" Content="Load Schema" Grid.Row="0" Height="20" Width="85" DockPanel.Dock="Left"
Margin="5" />
<Button x:Name="btn_loadJSON" Content="Load JSON" Grid.Row="0" Height="20" Width="85" DockPanel.Dock="Left"
Margin="5" IsEnabled="False"/>
<Button x:Name="btn_saveJSON" Content="Save JSON" Grid.Row="0" Height="20" Width="85" DockPanel.Dock="Left"
Margin="5" IsEnabled="False"/>
<Label/>
</DockPanel>
</Grid>
</Window>

MVVM Wait Cursor how to set the.wait cursor during invocation of a command?

I am using it successfully in my application:

/// <summary>
/// Contains helper methods for UI, so far just one for showing a waitcursor
/// </summary>
public static class UIServices
{
/// <summary>
/// A value indicating whether the UI is currently busy
/// </summary>
private static bool IsBusy;

/// <summary>
/// Sets the busystate as busy.
/// </summary>
public static void SetBusyState()
{
SetBusyState(true);
}

/// <summary>
/// Sets the busystate to busy or not busy.
/// </summary>
/// <param name="busy">if set to <c>true</c> the application is now busy.</param>
private static void SetBusyState(bool busy)
{
if (busy != IsBusy)
{
IsBusy = busy;
Mouse.OverrideCursor = busy ? Cursors.Wait : null;

if (IsBusy)
{
new DispatcherTimer(TimeSpan.FromSeconds(0), DispatcherPriority.ApplicationIdle, dispatcherTimer_Tick, System.Windows.Application.Current.Dispatcher);
}
}
}

/// <summary>
/// Handles the Tick event of the dispatcherTimer control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
private static void dispatcherTimer_Tick(object sender, EventArgs e)
{
var dispatcherTimer = sender as DispatcherTimer;
if (dispatcherTimer != null)
{
SetBusyState(false);
dispatcherTimer.Stop();
}
}
}

This has been taken from here. Courtsey huttelihut.

You need to call the SetBusyState method every time you think you are going to perform any time consuming operation. e.g.

...
UIServices.SetBusyState();
DoProcessing();
...

This will automatically change your cursor to wait cursor when the application is busy and back to normal when idle.

Change mouse cursor to stop pointer on hover on disabled button in WPF

Since you won't be able to trigger events with a disable control, I suggest placing a transparent rectangle over it, which will handle that for you:

<Button x:Name="Button1" IsEnabled="False"/>
<Rectangle Opacity="0" Fill="Transparent">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Button1, Path=IsEnabled}"
Value="False">
<Setter Property="Cursor" Value="No"/>
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>

The rectangle is collapsed when button is not enabled, so that it would allow button events to trigger. When the button is enabled, rectangle becomes visible (with 0 opacity and transparent background) and causes No cursor to appear when moused over.

EDIT:

Per comments, here's a working sample (which also attempts to resolve an issue OP is having with enabled button canceling behavior):

<Window x:Class="WpfApplication.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"
xmlns:local="clr-namespace:WpfApplication"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center"
HorizontalAlignment="Center">
<!-- Regular Button-->
<Button Width="120" Height="22" Margin="5"/>

<!--Custom Button-->
<Grid Width="120" Height="22" Margin="5">
<Button x:Name="Button1" IsEnabled="False"/>
<Rectangle Opacity="0" Fill="Transparent">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Button1, Path=IsEnabled}"
Value="False">
<Setter Property="Cursor" Value="No"/>
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
</Grid>
</StackPanel>
</Grid>
</Window>

Here's the demo:

Sample Image

I recommend creating a custom control using similar XAML, or, at the very least, create a template, so that you may reuse it.

Is is possible to change cursor blink rate and cursor movement speed in wpf?

WPF basically respects Windows's control panel settings of the blink rate. So does Word 2019 on my system. If you want to change the rate on your textbox, your only option is to disable the built-in caret (text cursor), and draw it yourself.

The following is shamelessly stolen inspired by this article, with some kinks ironed out:

  • SelectionChanged triggers too early when TextBox height is not a full multiple of line height causing buggy cursor positioning. Changed to LayoutUpdated.
  • Caret.Height respects the text height, instead of hardcoded.

Now on to the magic. Try this on your MainWindow.xaml:

<Grid x:Name="YouNeedAGridToContainTheTextBoxAndCanvas">

<TextBox x:Name="CustomTextBox"
FontSize="20"
AcceptsReturn="True" TextWrapping="Wrap"
CaretBrush="Transparent" />
<!--CaretBrush must be Transparent, as we will draw manually below-->

<Canvas ClipToBounds="True">
<Border x:Name="Caret"
Width="4"
Visibility="Collapsed"
Background="Transparent"> <!--Start drawing Transparent-->
<Border.Triggers>
<EventTrigger RoutedEvent="Border.Loaded">
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<ColorAnimationUsingKeyFrames
Storyboard.TargetProperty="Background.Color"
FillBehavior="HoldEnd">
<ColorAnimationUsingKeyFrames.KeyFrames>
<!--Ease to Red in 1sec-->
<EasingColorKeyFrame KeyTime="0:0:1.0" Value="Red"/>
<!--Ease back into Transparent in another 1sec-->
<EasingColorKeyFrame KeyTime="0:0:2.0" Value="Transparent" />
</ColorAnimationUsingKeyFrames.KeyFrames>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
</Border>
</Canvas>

</Grid>

You then need to manually update the drawing position by using code behind in your MainWindow.xaml.cs:

public MainWindow() //Constructor
{
InitializeComponent();

CustomTextBox.LayoutUpdated += (_, _) => {
var rect = CustomTextBox.GetRectFromCharacterIndex(CustomTextBox.CaretIndex);
if (rect.IsEmpty) return;
Canvas.SetLeft(Caret, rect.Left);
Canvas.SetTop(Caret, rect.Top);
Caret.Height = rect.Height;
};
CustomTextBox.LostFocus += (_, _) => Caret.Visibility = Visibility.Collapsed;
CustomTextBox.GotFocus += (_, _) => Caret.Visibility = Visibility.Visible;
CustomTextBox.Focus();
}

Feel free to tweak the color animation, adding frames as needed and playing with the KeyTime for faster/slower pulsing. Use <DiscreteColorKeyFrame> instead of <EasingColorKeyFrame> if you want a hard blink instead of pulsing.

WPF Wait Cursor With BackgroundWorker Thread

What seems to be happening here is that WPF is ignoring the Cursor setting on the disabled window. The following workaround seems to work: instead of disabling the window itself, disable the content of the window:

C#:

((UIElement)Content).IsEnabled = false;
Cursor = Cursors.Wait;

// and in RunWorkerCompleted handler:
((UIElement)Content).IsEnabled = true;
Cursor = Cursors.Arrow;

Visual Basic:

DirectCast(Content, UIElement).IsEnabled = False
Cursor = Cursors.Wait

' and in RunWorkerCompleted handler:'
DirectCast(Content, UIElement).IsEnabled = True
Cursor = Cursors.Arrow


Related Topics



Leave a reply



Submit