Text Writing Animation like word2013 [duplicate] - c#

This question already has answers here:
Is there any way I can integrate the MS Office Smooth Typing in a C# application?
(2 answers)
Closed 9 years ago.
I was wondering, if I can make a TextBox or any control that you can write some text on it, to be like Word 2013, the animation experience is very good.
I am now able to do type of animation on the control itself (TextBox,...), but to do this type of animation to the cursor or on the text itself this is new.

You could create a WPF UserControl or custom control which inherits from the default WPF textbox. I was able to create a textbox that animates the cursor position with the following method:
1-Create a user control and add a textbox to it.
2-Add a canvas with a rectangle inside it (the rectangle is your new cursor).
3-Set the Texboxes CaretBrush to transparent.
4-In the UserControl's code-behind create a method to animate the cursor when the cursor position changes.
5-Call the animation method from step 4 when certain events happen which would change the cursor position.
Example:
UserControl XAML
<UserControl
x:Class="YourNamespace.AnimatedCursorTextBox"
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="23"
d:DesignWidth="300"
xmlns:c="clr-namespace:System.Windows.Controls;assembly=PresentationFramework"
Name="Control">
<UserControl.Resources>
<c:BooleanToVisibilityConverter
x:Key="BoolToVisibility" />
</UserControl.Resources>
<Grid>
<TextBox
Name="MainTextBox"
CaretBrush="Transparent"
SelectionChanged="MainTextBox_SelectionChanged"
TextChanged="MainTextBox_TextChanged"
GotKeyboardFocus="MainTextBox_GotKeyboardFocus" />
<Canvas
Visibility="{Binding IsKeyboardFocusWithin,
ElementName=Control,
Converter={StaticResource BoolToVisibility}}"
Height="{Binding ActualHeight, ElementName=MainTextBox}"
Width="{Binding ActualWidth, ElementName=MainTextBox}">
<Rectangle
HorizontalAlignment="Left"
Name="Caret"
Width="1"
Fill="Black" />
</Canvas>
</Grid>
</UserControl>
Code-Behind:
public partial class AnimatedCursorTextBox : UserControl
{
private DoubleAnimation cursorAnimation = new DoubleAnimation();
public AnimatedCursorTextBox()
{
InitializeComponent();
}
private void UpdateCaretPosition()
{
var rectangle = MainTextBox.GetRectFromCharacterIndex(MainTextBox.CaretIndex);
Caret.Height = rectangle.Bottom - rectangle.Top;
Canvas.SetTop(Caret, rectangle.Top);
Canvas.SetBottom(Caret, rectangle.Bottom);
var left = Canvas.GetLeft(Caret);
if (!double.IsNaN(left))
{
cursorAnimation.From = left;
cursorAnimation.To = rectangle.Right;
cursorAnimation.Duration = new Duration(TimeSpan.FromSeconds(.05));
Caret.BeginAnimation(Canvas.LeftProperty, cursorAnimation);
}
else
{
Canvas.SetLeft(Caret, rectangle.Right);
}
}
private void MainTextBox_SelectionChanged(object sender, RoutedEventArgs e)
{
UpdateCaretPosition();
}
private void MainTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
UpdateCaretPosition();
}
private void MainTextBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
UpdateCaretPosition();
}
}
Note: This isn't a comprehensive solution because it doesn't handle the animation of highlighting selected text and it doesn't hide the cursor when text is highlighted, but it is a start. I recommend creating this as a custom control inheriting from TextBox and then do the layout of the control in the textbox's default style's template rather than using a UserControl. That way you can preserve all the functionality of TextBox but still get the new animation features. For more information about Custom Controls in WPF see this article on codeproject.
To change the speed of the animation just change the duration of the cursorAnimation.

Related

UWP: How do you make a Border a click through shield?

I have situation where I want an overlay control to block UI interactions on a Page for everything that is behind a border. I have tried setting Border.ManipulationMode to False. I have set IsTapEnabled, IsRightTapEnabled, IsDoubleTapEnabled, and IsHitTestVisible to False.
I also tried subscribing to the Tapped and PointerEntered events, and setting the args Handled property to true. After all of this I can still click on Buttons through the border, and invoke their commands. Below are a few screenshots for context:
Page with no overlay
Page now has what should be an overlay that blocks controls behind it
A button capturing PointerOver that shouldn't be
Here is the UserControl xaml that becomes the overaly on the Page:
<UserControl x:Class="PocMvvmToolkitApp.Dialogs.DialogShell"
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"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid x:Name="overlayGrid"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<!--dialogShield is the Border that I want to prevent click through on-->
<Border x:Name="dialogShield"
Background="#AAFFFFFF"
IsHitTestVisible="False"
ManipulationMode="None"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
IsDoubleTapEnabled="False"
IsHoldingEnabled="False"
IsRightTapEnabled="False"
IsTapEnabled="False"/>
<Border x:Name="dialogBorder"
BorderBrush="Black"
BorderThickness="1" />
</Grid>
Attempting to handle the events:
public DialogShell()
{
this.InitializeComponent();
this.allDialogs = new List<ExtendedContentDialog>();
this.visibleDialogs = new List<ExtendedContentDialog>();
////Doesn't work
this.dialogShield.PointerEntered += this.OnModalShieldPointerEntered;
this.dialogShield.Tapped += this.OnModalShieldTapped;
}
private void OnModalShieldTapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
{
////Doesn't block click through
e.Handled = true;
}
private void OnModalShieldPointerEntered(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
e.Handled = true;
}
On the Page.xaml.cs here is where I add or remove the DialogShell control to the parent Grid on the page:
private void OnDialogStackChanged(Args.DialogStackChangedEventArgs args)
{
switch (args.Context)
{
case Args.DialogStackChangedContext.Showing:
if (this.dialogShell == null)
{
this.dialogShell = new DialogShell();
this.dialogShell.ShowDialog(args.Dialog);
this.rootGrid.Children.Add(this.dialogShell);
Grid.SetColumnSpan(this.dialogShell, 2);
}
break;
case Args.DialogStackChangedContext.Closing:
if (this.dialogShell != null)
{
this.dialogShell.RemoveDialog(args.Dialog);
if (this.dialogShell.AllDialogs.Count == 0)
{
this.rootGrid.Children.Remove(this.dialogShell);
this.dialogShell = null;
}
}
break;
}
}
Any help with this Border situation would be appreciated. Before someone recommends using ContentDialog, please don't, I have my reasons for this setup. Thanks!

UserControl hidden, Zindex misused?

In my main page I try to show a list of stuff, and on this stuff a userControl as an overlay. In fact I never see it. (In the design view, my userControl is oaky)
XAML MainPage
<Grid>
<Grid x:name="MyPage">
<!-- All this part is visible -->
//Button
//Button
//nice Pic
//Button
</Grid>
<cat:CatPagecontrol x:Name="CatTool" Visibility="Visible" HorizontalAlignment="Center" VerticalAlignment="Center">
<cat:CatPagecontrol.Transitions>
<TransitionCollection>
<PopupThemeTransition/>
</TransitionCollection>
</cat:CatPagecontrol.Transitions>
</cat:CatPagecontrol>
<!-- EDIT I remove the Grid "CatGrid" And the ZIndex -->
</Grid>
I try to switch the ZIndex, no results.
C# File
public MainView()
{
this.CatTool = new CatPagecontrol();
//this.CatTool.Visibility = Visibility.Collapsed;
}
private void showCatSelector()
{
this.CatTool.Visibility = Visibility.Visible;
}
After that I need that one of my buttons show the overlay when clicked.
If you know how to show it, I'm yours. Thanks.
edit : solution find.
Voila !
I've find my problem :
public CatPagecontrol()
{
this.InitializeComponent();
}
I just Initialized in the correct section.

How to attach a Thumb to a TextBlock?

I have the following XAML:
<Window x:Class="thumb_test.MainWindow" Title="MainWindow" ... >
<Grid>
<Canvas>
<Thumb Canvas.Top="25" Canvas.Left="25" Width="50" Height="50"
Name="_thumb1" DragStarted="ThumbStart" DragDelta="ThumbMoved" >
</Thumb>
</Canvas>
</Grid>
</Window>
And the following is the corresponding code-behind:
void ThumbStart(object sender, DragStartedEventArgs e)
{
_originalLeft = Canvas.GetLeft(_thumb1);
_originalTop = Canvas.GetTop(_thumb1);
}
void ThumbMoved(object sender, DragDeltaEventArgs e)
{
double left = _originalLeft + e.HorizontalChange;
double top = _originalTop + e.VerticalChange;
Canvas.SetLeft(_thumb1, left);
Canvas.SetTop(_thumb1, top);
_originalLeft = left;
_originalTop = top;
}
The above displays a rectangle, which can be dragged around on the canvas.
My question: How can I associate this Thumb with a TextBlock, such that the Thumb overlays the TextBlock (with the Thumb being transparent) and I can drag the TextBlock around? (PS: Believe me, what I have tried so far is not worth showing here.)
My ultimate goal is to be able to drag TextBlocks around, so I am open to other approaches. I would like to operate on a Canvas, though.
I am using VS2010 on Win 7, with .NET 4.0.
have you read Dragging Elements in a Canvas ?
or this easy way(that i never saw until now -google) How to make any UI element drag-able using Behaviors in WPF

Why does the MouseMove event not work if mouse loses focus on object?

I basically have a simple problem in my program that I just want to make sure goes right. It should on the click of the mouse button add the MouseEventHandler and then move the circle along with the mouse until the event handler gets removed. I simplified the code to the very basics:
XAML:
<Window x:Class="WpfApplication1.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">
<Grid Name="grid1" Background="White" MouseLeftButtonUp="grid_MouseUp">
<Ellipse Height="50" HorizontalAlignment="Left" Margin="12,12,0,0" Name="ellipse1" Stroke="{x:Null}" VerticalAlignment="Top" Width="50" Fill="Black" MouseLeftButtonDown="ellipse1_MouseDown" />
</Grid>
</Window>
C#:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private static Point _oldPoint = new Point(), _newPoint = new Point();
private void ellipse1_MouseDown(object sender, MouseButtonEventArgs e)
{
_oldPoint = e.GetPosition(grid1);
grid1.MouseMove += new MouseEventHandler(grid_MouseMove);
}
private void grid_MouseUp(object sender, MouseButtonEventArgs e)
{
grid1.MouseMove -= new MouseEventHandler(grid_MouseMove);
}
private void grid_MouseMove(object sender, MouseEventArgs e)
{
_newPoint = e.GetPosition(grid1);
ellipse1.Margin = new Thickness(ellipse1.Margin.Left - _oldPoint.X + _newPoint.X, ellipse1.Margin.Top - _oldPoint.Y + _newPoint.Y, 0, 0);
_oldPoint = _newPoint;
}
}
Now in general this code works fine and I think is quite neat as it doesn't check the movement of the mouse until one actually presses the button. However, my question is as follows:
I had to add the MouseMove event to the grid rather than to the circle, because once the mouse pointer loses focus of the circle (by moving the mouse too fast) it doesn't trigger the MouseMove event anymore. But why exactly does that happen? At the beginning of the event the mouse was definitely above the circle and then it moved. Yes, it moved away from the circle but shouldn't that still trigger the event?
You can capture the mouse and handle all events in your ellipse.
<Grid Name="grid1" Background="White">
<Ellipse Height="50" HorizontalAlignment="Left" Margin="12,12,0,0" Name="ellipse1" Stroke="{x:Null}" VerticalAlignment="Top" Width="50" Fill="Black"
MouseLeftButtonDown="ellipse1_MouseDown" MouseLeftButtonUp="ellipse1_MouseUp" />
</Grid>
with this code behind
private void ellipse1_MouseDown(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(ellipse1);
_oldPoint = e.GetPosition(grid1);
ellipse1.MouseMove += new MouseEventHandler(ellipse1_MouseMove);
}
private void ellipse1_MouseUp(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(null);
ellipse1.MouseMove -= new MouseEventHandler(ellipse1_MouseMove);
}
I've moved and renamed grid_MouseMove to ellipse1_MouseMove.
Adding to what Peter said, if you use the Grid.MouseDown event and checked if the oldPoint is within Ellipse and have then handled the MouseMove event, this odd behavior wont be seen.
I also suggest exploring drag events.
A control only gets the mouse-events as long as the mouse is hovering over that particularly control.
If moving to a new control, the mouse is getting unhooked from the old control and hooked to the new control.
There are ways where you can create a global hook attached to the entire process, but I guess this is not what we are talking about.

wpf popup doesn't close automatically when datagrid inside popup captures the mouse

I have a popup with StaysOpen=False so I want to close it by clicking anywhere outside of popup. Inside a popup I have a DataGrid. If I open popup and then click somewhere else the popup will be closed. But it won't happen if before clicking outside of popup I will click on column header in DataGrid. Test XAML:
<Window x:Class="Test.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" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Black">
<Grid>
<ToggleButton x:Name="btn" VerticalAlignment="Top">Open</ToggleButton>
<Popup StaysOpen="False" IsOpen="{Binding IsChecked, ElementName=btn}" >
<DataGrid Width="150" Height="150">
<DataGrid.Columns>
<DataGridTextColumn Header="Column" />
</DataGrid.Columns>
</DataGrid>
</Popup>
</Grid>
</Window>
I think that it happens because column header captures the mouse on click and popup doesn't receive mouse events anymore. I've tried to add a handler on LostMouseCapture event in order to capture mouse back by popup but it doesn't seem to work that easy. Any ideas?
Maybe it will help.
Attached behavior:
public class DataGridColumnHeaderReleaseMouseCaptureBehavior {
public static DataGrid GetReleaseDGCHeaderBehavior(DependencyObject obj) {
return (DataGrid)obj.GetValue(ReleaseDGCHeaderBehaviorProperty);
}
public static void SetReleaseDGCHeaderBehavior(DependencyObject obj, Boolean value) {
obj.SetValue(ReleaseDGCHeaderBehaviorProperty, value);
}
public static readonly DependencyProperty ReleaseDGCHeaderBehaviorProperty =
DependencyProperty.RegisterAttached("ReleaseDGCHeaderBehavior",
typeof(DataGrid),
typeof(DataGridColumnHeaderReleaseMouseCaptureBehavior),
new UIPropertyMetadata(default(DataGrid), OnReleaseDGCHeaderBehaviorPropertyChanged));
private static Popup _popup;
private static void OnReleaseDGCHeaderBehaviorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var oldGrid = (DataGrid)e.OldValue;
if (oldGrid != null)
oldGrid.MouseLeave -= OnMouseLeave;
var refSender = d as Popup;
_popup = refSender;
if (refSender != null) {
var refGrid = e.NewValue as DataGrid;
if (refGrid != null) {
refGrid.MouseLeave += OnMouseLeave;
}
}
}
static void OnMouseLeave(object sender, MouseEventArgs args) {
if (_popup != null)
typeof(Popup).GetMethod("EstablishPopupCapture", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Invoke(_popup, null);
}
}
XAML:
<Popup x:Name="popup"
bhvrs:DataGridColumnHeaderReleaseMouseCaptureBehavior.ReleaseDGCHeaderBehavior="{Binding ElementName=dataGrid}">
<DataGrid x:Name="dataGrid"/>
</Popup>
I think you've stumbled onto just a plain old bug. I've reproduced this and could not find a reasonable way to get it working. I think you should file a bug with Microsoft. It seems like a component that captures the mouse and the uncaptures it doesn't restore the capture to the originally capturing component.
I had a similar problem recently altough not exactly the same, and it was in Silverlight. I hacked my way through it by searching the required control (in your case the popup I guess) with the GetTemplatedParent function, in the required event handler of the 'misbehaving' control, and programatically do what I wanted to do on it.
This is not a nice solution, and doesn't solve all the problems, but you can give it a try. Be sure you comment what have you done, because it can turn into a mess.
i had the same problem,and did something like this:
private void YourDataGrid_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
YourDataGrid.CaptureMouse();
YourDataGrid.ReleaseMouseCapture();
}
but i'm looking for something better yet...

Categories

Resources