I want to have a border highlight animation on my app - c#

I want after the button i clicked that there comes a animation and lands on the picture that is the number of the _random but i cant find anything on the google
ive tried to google and ask around but still havent got what i want
public sealed partial class FilePage : Page
{
DataPage value = new DataPage();
Random _random = new Random();
private int time = 0;
DispatcherTimer Timer;
public FilePage()
{
this.InitializeComponent();
}
private void ButtonClick1(object sender, RoutedEventArgs e)
{
//////////
//////////cut some off to keep this short (turning the border black again)
//////////
Timer = new DispatcherTimer();
Timer.Interval = new TimeSpan(0, 0, 3);
Timer.Tick += Timer_Tick;
Timer.Start();
}
public void Timer_Tick(object sender, object e)
{
int value = _random.Next(1, 13);
((Grid)gMainGrid.FindName($"g{value}")).BorderBrush = new SolidColorBrush(Colors.White);
Timer.Stop();
SpinnerSecond.Visibility = Visibility.Collapsed;
DataWatch.valueWatch = value;
RollKnop.Visibility = Visibility.Visible;
}
}
}
so i want to have a animation that goes over the borders like this:
https://learn.microsoft.com/en-us/windows/apps/images/fluent/traveling-focus-fullscreen-light-rf.gif for like the 3 seconds and then land on the right one, im sorry if i sound like a demander but im already googling for 2 days

Pretty sure that you have to use ControlPaint.DrawBorder if the pictures are in pictureboxes, you draw for one picture, after a short delay you remove it, then draw it on the other, etc
After 3 secondes, you keep that going until it lands on the good picture then you stop everything
EDIT : You might want to check that if that hasn't been already done : How Do I Create a Colored Border on a PictureBox Control?

To short, you can create a loop that traverses the elements inside the container and sets the BorderBrush and BorderThickness for them.
This is a simple code example:
ColorBorderPage.xaml
<StackPanel>
<controls:WrapPanel x:Name="ItemsContainer" HorizontalAlignment="Center" Width="160" Height="120" Margin="0,50">
<StackPanel Background="Gray" Width="100" Height="50" Margin="0,0,10,10"/>
<StackPanel Background="Gray" Width="50" Height="50" Margin="0,0,0,10"/>
<StackPanel Background="Gray" Width="160" Height="50"/>
</controls:WrapPanel>
<Button Content="Click Me" Click="Button_Click" HorizontalAlignment="Center"/>
</StackPanel>
I created a Panel called ItemsContainer, which replaces the image with a StackPanel and add a button to trigger the animation.
ColorBorderPage.xaml.cs
private async void Button_Click(object sender, RoutedEventArgs e)
{
int count = ItemsContainer.Children.Count;
int index = 0;
while (true)
{
var item = ItemsContainer.Children[index] as StackPanel;
item.BorderBrush = new SolidColorBrush(Colors.LightGreen);
item.BorderThickness = new Thickness(3);
await Task.Delay(3000);
item.BorderThickness = new Thickness(0);
index = index == count - 1 ? 0 : index + 1;
}
}
In the code, by first getting the number of child elements in the container, then setting the Border one by one through the while loop, and restarting when looping to the end.
According to your animation requirements, you can use Task.Delay(), which will delay the specified time before proceeding to the next step.
This is just an example, but it should be able to meet your needs, you just need to replace the StackPanel with an Image.
Best regards.

Related

UWP Scroll Text from end to start

I am implementing a scrolling text that when pointer enters it, it starts scrolling its content.
I am able to get it scrolling using the code below:
private DispatcherTimer ScrollingTextTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(16) };
ScrollingTextTimer.Tick += (sender, e) =>
{
MainTitleScrollViewer.ChangeView(MainTitleScrollViewer.HorizontalOffset + 3, null, null);
if (MainTitleScrollViewer.HorizontalOffset == MainTitleScrollViewer.ScrollableWidth)
{
MainTitleScrollViewer.ChangeView(0, null, null);
ScrollingTextTimer.Stop();
}
};
XAML:
<ScrollViewer
x:Name="MainTitleScrollViewer"
Grid.Row="0"
Grid.Column="1"
Margin="10,5"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Disabled">
<TextBlock
x:Name="MainTitleTextBlock"
VerticalAlignment="Bottom"
FontSize="24"
Foreground="White" />
</ScrollViewer>
However, there is an additional feature that I want to implement. When the text scrolls to its end, I don't want it to scroll back to the start. I want it to keep scrolling to the start. You can see what I mean from the screenshots I posted below. The screenshots are from Groove Music. You may need to check it out if I didn't explain my question well.
A possible solution might be doubling the text and putting some space between them. But I don't know when to stop scrolling if so.
The effect of this kind of marquee is recommended to use Storyboard. The timer may cause lack due to time interval.
Here is a complete demo, I hope to help you.
xaml
<Grid>
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" BorderBrush="Gray" BorderThickness="1" Padding="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Source="ms-appx:///Assets/StoreLogo.png" Width="100" Height="100" VerticalAlignment="Center"/>
<StackPanel Grid.Column="1" Margin="20,0,0,0" VerticalAlignment="Center">
<ScrollViewer Width="200"
PointerEntered="ScrollViewer_PointerEntered"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
PointerExited="ScrollViewer_PointerExited">
<TextBlock FontSize="25" x:Name="TitleBlock">
<TextBlock.RenderTransform>
<TranslateTransform X="0"/>
</TextBlock.RenderTransform>
</TextBlock>
</ScrollViewer>
<TextBlock FontSize="20" FontWeight="Bold" Text="Gotye" Margin="0,10,0,0"/>
</StackPanel>
</Grid>
</Grid>
xaml.cs
Storyboard _scrollAnimation;
public ScrollTextPage()
{
this.InitializeComponent();
string text = "How about you?";
TitleBlock.Text = text + " " + text;
}
private void ScrollViewer_PointerEntered(object sender, PointerRoutedEventArgs e)
{
AnimationInit();
_scrollAnimation.Begin();
}
private void ScrollViewer_PointerExited(object sender, PointerRoutedEventArgs e)
{
_scrollAnimation.Stop();
}
public void AnimationInit()
{
_scrollAnimation = new Storyboard();
var animation = new DoubleAnimation();
animation.Duration = TimeSpan.FromSeconds(5);
animation.RepeatBehavior = new RepeatBehavior(1);
animation.From = 0;
// Here you need to calculate based on the number of spaces and the current FontSize
animation.To = -((TitleBlock.ActualWidth/2)+13);
Storyboard.SetTarget(animation, TitleBlock);
Storyboard.SetTargetProperty(animation, "(UIElement.RenderTransform).(TranslateTransform.X)");
_scrollAnimation.Children.Add(animation);
}
Simply put, scrolling the TextBlock horizontally is more controllable than scrolling the ScrollViewer.
The idea is similar to yours, using a string stitching method to achieve seamless scrolling, and calculate the width of the space by the current font size, so as to accurately scroll to the beginning of the second string.
Best regards.
This is my way of doing it and source code is here(xaml) and here(csharp):
I created a UserControl called ScrollingTextBlock.
This is XAML content of the UserControl.
<Grid>
<ScrollViewer x:Name="TextScrollViewer">
<TextBlock x:Name="NormalTextBlock" />
</ScrollViewer>
<ScrollViewer x:Name="RealScrollViewer">
<TextBlock x:Name="ScrollTextBlock" Visibility="Collapsed" />
</ScrollViewer>
</Grid>
Basically, you need two ScrollViewers that overlaps.
The first ScrollViewer is for detecting if the text is scrollable. And the TextBlock in it is for putting the text.
The second ScrollViewer is the real ScrollViewer. You will be scrolling this one not the first one. And the TextBlock in it will have its Text equal to
ScrollTextBlock.Text = NormalTextBlock.Text + new string(' ', 10) + NormalTextBlock.Text
The new string(' ', 10) is just some blank space to make your text not look concatenated tightly, which you can see from the image in the question. You can change it into whatever you want.
Then in the csharp code you need (explanations are in the comments):
// Using 16ms because 60Hz is already good for human eyes.
private readonly DispatcherTimer timer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(16) };
public ScrollingTextBlock()
{
this.InitializeComponent();
timer.Tick += (sender, e) =>
{
// Calculate the total offset to scroll. It is fixed after your text is set.
// Since we need to scroll to the "start" of the text,
// the offset is equal the length of your text plus the length of the space,
// which is the difference of the ActualWidth of the two TextBlocks.
double offset = ScrollTextBlock.ActualWidth - NormalTextBlock.ActualWidth;
// Scroll it horizontally.
// Notice the Math.Min here. You cannot scroll more than offset.
// " + 2" is just the distance it advances,
// meaning that it also controls the speed of the animation.
RealScrollViewer.ChangeView(Math.Min(RealScrollViewer.HorizontalOffset + 2, offset), null, null);
// If scroll to the offset
if (RealScrollViewer.HorizontalOffset == offset)
{
// Re-display the NormalTextBlock first so that the text won't blink because they overlap.
NormalTextBlock.Visibility = Visibility.Visible;
// Hide the ScrollTextBlock.
// Hiding it will also set the HorizontalOffset of RealScrollViewer to 0,
// so that RealScrollViewer will be scrolling from the beginning of ScrollTextBlock next time.
ScrollTextBlock.Visibility = Visibility.Collapsed;
// Stop the animation/ticking.
timer.Stop();
}
};
}
public void StartScrolling()
{
// Checking timer.IsEnabled is to avoid restarting the animation when the text is already scrolling.
// IsEnabled is true if timer has started, false if timer is stopped.
// Checking TextScrollViewer.ScrollableWidth is for making sure the text is scrollable.
if (timer.IsEnabled || TextScrollViewer.ScrollableWidth == 0) return;
// Display this first so that user won't feel NormalTextBlock will be hidden.
ScrollTextBlock.Visibility = Visibility.Visible;
// Hide the NormalTextBlock so that it won't overlap with ScrollTextBlock when scrolling.
NormalTextBlock.Visibility = Visibility.Collapsed;
// Start the animation/ticking.
timer.Start();
}

How to update the draw order of a list of controls in WPF

I made a custom WPF editor and I am having trouble getting a list of screen control objects (buttons, text boxes, etc) to be displayed in the correct draw order. Here is a visual of my current setup:
I have the control object window working just fine and I can see when the list is changed.
My problem is this: Say that I selected object 3 and pressed the up button. The object should move up in the list (which it does!) BUT the draw order stays the same. Meaning that object 3 should draw behind object 2 and its not doing that. I don't know why.
Here is my code:
private void MoveUp_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < controlObjectList.Count; i++)
{
if (controlObjectList[i].IsSelected)
{
// Copy the current item
var selectedItem = controlObjectList[i];
int newindex = Math.Abs(i - 1);
// Remove the item
controlObjectList.RemoveAt(i);
// Finally add the item at the new index
controlObjectList.Insert(newindex, selectedItem);
}
}
RefreshControlObjectList(controlObjectList);
}
private void MoveDown_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < screenDesigner.m_ParentScreenObject.controlObjects.Count; i++)
{
if (controlObjectList[i].IsSelected)
{
// Copy the current item
var selectedItem = controlObjectList[i];
int newindex = i + 1;
if(newindex < controlObjectList.Count)
{
// Remove the item
controlObjectList.RemoveAt(i);
// Finally add the item at the new index
controlObjectList.Insert(newindex, selectedItem);
}
}
}
RefreshControlObjectList(controlObjectList);
}
private void RefreshControlObjectList(List<ItemsList> newList)
{
newList.Items.Clear();
foreach (ItemsList il in controlObjectList)
{
listObjects.Items.Add(il);
}
//I know this is where I should place the logic for the draw order...
}
#endregion
}
What I'm trying to figure out is how can I refresh the screen in order to see the correct draw order of my objects? Is it possible? Many thanks in advance!
BringForward and SendBackward commands can be accomplished both ways by [1] changing the order of the children or [2] by changing their ZIndex, in fact before the introduction of the ZIndex dependency properties it was only possible by changing the order of the children in the container.
Do you have a complete code sample by any chance? If not here is an example of a sample markup and code which is proving that it is indeed working, but be aware of possible performance impacts of that approach since ZIndex was introduced to fix them.
<Canvas Name="container" MouseDown="OnMouseDown">
<Ellipse Canvas.Left="50" Canvas.Top="10" Fill="Red" Height="100" Width="100"></Ellipse>
<Ellipse Canvas.Left="100" Canvas.Top="20" Fill="Green" Height="100" Width="100"></Ellipse>
<Ellipse Canvas.Left="150" Canvas.Top="30" Fill="Blue" Height="100" Width="100"></Ellipse>
</Canvas>
private void OnMouseDown(object sender, MouseButtonEventArgs e)
{
var uiElement = e.Source as Ellipse;
container.Children.Remove(uiElement);
container.Children.Add(uiElement);
}
You would need to figure out if the list of objects you are manipulating by adding and removing the children is indeed the one. It would be helpful to get some context around the variables controlObjectList and listObjects to see who they belong to.

How to remove line on tapped point inside canvas in Windows Phone 8?

Im trying to draw a line with finger on windows phone canvas, i Done this but when i try to remove/clear that line it's Removing all Elements in that Canvas ,
ContentPanelCanvas.Children.Clear();
Hear is My Complete Code:
XAML
<Canvas x:Name="ContentPanelCanvas" Grid.Row="1" Background="Transparent" Margin="12,0,12,0">
<Grid Width="450" Height="600">
<Button x:Name="clickMeBtn" Height="72"
Width="200"
Content="Click Me"
HorizontalAlignment="Center"
VerticalAlignment="Center" Click="clickMeBtn_Click" />
</Grid>
</Canvas>
C# Code is Like this :
public MainPage()
{
InitializeComponent();
this.ContentPanelCanvas.MouseMove += new MouseEventHandler(ContentPanelCanvas_MouseMove);
this.ContentPanelCanvas.MouseLeftButtonDown += new MouseButtonEventHandler(ContentPanelCanvas_MouseLeftButtonDown);
}
void ContentPanelCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
currentPoint = e.GetPosition(ContentPanelCanvas);
oldPoint = currentPoint;
}
void ContentPanelCanvas_MouseMove(object sender, MouseEventArgs e)
{
currentPoint = e.GetPosition(this.ContentPanelCanvas);
line = new Line() { X1 = currentPoint.X, Y1 = currentPoint.Y, X2 = oldPoint.X, Y2 = oldPoint.Y };
line.Stroke = new SolidColorBrush(Colors.White);
line.StrokeThickness = 10;
this.ContentPanelCanvas.Children.Add(line);
oldPoint = currentPoint;
}
private void clickMeBtn_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Hello Every One ");
ContentPanelCanvas.Children.Clear();
}
Code is Executing Without Error , But it's Removing button to , How can i Remove Only Lines I Draw
Well, the code is doing exactly what you wrote, it is clearing all children of the ContentPanelCanvas. If you only want to remove the lines, then only remove the lines:
foreach (var line in ContentPanelCanvas.Children.OfType<Line>().ToList())
ContentPanelCanvas.Children.Remove(line);
You can use
ContentPanelCanvas.Children.Remove(Line);
or remove children by index
ContentPanelCanvas.Children.RemoveAt(1);
If you clear the canvas it will "Removes all elements from a UIElementCollection."
You should create an event handler with line for example tap event handler , once tap you should hold the line control in another control to remove, then in button click handler remove it like this
ContentPanelCanvas.Children.Remove(controlToDelete);
controlToDelete is the control you hold to delete from the line tap handler i.e line control

UserControl BringIntoView() not working properly

Background:
I have a usercontrol defined in a ScrollViewer along with a ContentControl, the ContentControl will be visible all the time, and within it there is a Button, when the button is clicked will set the usercontrol to Visible, and when the usercontrol shows (Visiblility="Visible") I want it to be scrolled into the view. I have
XAML
<ScrollViewer VerticalScrollBarVisibility="Auto" MaxHeight="465">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ContentControl Content="{Binding MyOtherViewModel}" Width="960" ></ContentControl>
<local:MyView IsVisibleChanged="MyView_IsVisibleChanged" Grid.Row="1" Visibility="{Binding IsNonCompliant, Converter={StaticResource BooltoVisible}, UpdateSourceTrigger=PropertyChanged}" />
</ScrollViewer>
Code Behind
private void MyView_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
(sender as Control).BringIntoView();
}
Problem: this is not working, or more precisely, my usercontrol scrolled into the view first then revert back to the bottom of the ScrollViewer in a blink.
Weird thing: show a messagebox before calling BringIntoView will correctly display my usercontrol into the middle of the view
Current hack solution: you can see this works even to close the Window immediately after its loaded
private void MyView_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
Window ss = new Window();
ss.Loaded += new RoutedEventHandler(ss_Loaded);
ss.ShowDialog();
(sender as Control).BringIntoView();
}
private void ss_Loaded(object sender, RoutedEventArgs e)
{
(sender as Window).Close();
}
Question: I know there must be something else going on, but I just can't identify it, but I really want to know what happened when a window showing with ShowDialog? Is this because it refreshes the window so that the BringIntoView will happen only after the usercontrol been loaded? (Not as the problem I have now: BringIntoView happened first, and then the window get refreshed and put the scrollbar back to the top). And what is the correct fix for my problem?
It looks like BringIntoView called before my Usercontrol getting rendered, as a result when it gets fully rendered, the scrollbar is revert back to the top (as I have described in my question). And thanks for the answer from #Evgeny posted for another question, I get a better solution now (less hack maybe?). Still want to see if there are better solutions.
private void MyView_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var border = (FrameworkElement)sender;
if (border.IsVisible)
{
//Window ss = new Window();
//ss.Loaded += new RoutedEventHandler(ss_Loaded);
//ss.ShowDialog();
using (BackgroundWorker bg = new BackgroundWorker())
{
bg.DoWork += new DoWorkEventHandler(bg_DoWork);
bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_RunWorkerCompleted);
Tuple<FrameworkElement, double> b = new Tuple<FrameworkElement, double>(border, border.Height);
bg.RunWorkerAsync(b);
}
}
}
private void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
(e.Result as UserControl).BringIntoView();
}
private void bg_DoWork(object sender, DoWorkEventArgs e)
{
int maxwait = 300 //not scrolled to the view is not a disaster, but if the program hangs forever it will be a disaster, so set this to prevent that from happening
while (maxwait!=0
&&
(e.Argument as Tuple<FrameworkElement, double>).Item1.ActualHeight != (e.Argument as Tuple<FrameworkElement, double>).Item2)
{
Thread.Sleep(1);
maxwait --;
}
e.Result = (e.Argument as Tuple<FrameworkElement, double>).Item1;
}
I cannot believe that using background worker is a correct solution for this! You can use LayoutUpdated event to easily find when control is loaded and finally displayed.
userControl.LayoutUpdated+=OnLayoutUpdated;
private bool loaded=false;
private void OnLayoutUpdated(object sender,EventArgs e)
{
if (!loaded && (view.ActualHeight > 0 || view.ActualWidth > 0))
{
// Unsubscribe or set a flag.
userControl.LayoutUpdated -= OnLayoutUpdated;
loaded = true;
}
}
So you can execute that code when layout is updated and height or width is set. This will means that control is loaded and displayed.
Than you can unsubscribe or set a flag that initialization is complated.

Handling horizontal swipe on control in WinRT

So let's say I have stackpanel on the left edge with width 200px. Now I want to handle horizontal swipe from left to right on this panel and show additional panel. Then handle swipe from right to left to hide it.
I tried handling page's ManipulationStarted and ManipulationDelta events, but it doesn't seem to have any effect at least with mouse. Any ideas, what could be an easy way to implement that?
What I've tried:
Handle page's swipe events and on the beginning of swipe check, if it was started in bounds of stackpanel, else I ignore it.
If swipe's delta was more then positive 40, looks like swipe was from left to right.
My XAML file:
// standard stuff of page
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Orientation="Vertical" Width="200" HorizontalAlignment="Left" Background="White" x:Name="Panel"/>
</Grid>
// continue standard stuff
C# file:
public MainPage()
{
this.InitializeComponent();
this.ManipulationDelta += MainPage_ManipulationDelta;
this.ManipulationStarted += MainPage_ManipulationStarted;
}
private void MainPage_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("heh");
if (e.Position.X < 200)
{
initialPoint = e.Position;
isSwiping = true;
}
}
private void MainPage_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
if (e.IsInertial && isSwiping)
{
Point currentPoint = e.Position;
if (currentPoint.X - initialPoint.X >= 40)
{
isSwiping = false;
e.Complete();
System.Diagnostics.Debug.WriteLine("finished swipe :)");
}
}
}
private Point initialPoint;
private Boolean isSwiping;
(Again omitted default empty page)
You need to set ManipulationMode on a control e.g. ManipulationMode="TranslateX" and have the control respond to hit-testing (i.e. if it does not have a background - set the Background to Transparent) to receive manipulation events.
Then again - why not just use a ListView that has built-in support for swipes?

Categories