how do compare a exactly position of MediaElement while playing - c#

i have a single video (duration: 3 seconds) and i need to create 2 states
1- the video should always reach the second 1.5 and play it from the start.
TimeSpan ts = new TimeSpan(0, 0, 0, 1, 500);
TimeSpan ts_Start = new TimeSpan(0, 0, 0, 0, 0);
if (mediaElement.position == ts)
mediaElement.position = ts_Start; //doesnt work this block code
2- when i press a button, the video should play the full video (3 seconds). (simple flag, boolean)
so my question is, how do i know when the mediaelement.position = 1.5 seconds ??.... i thought of a method such as playing or something like that.

If you get the MediaElement's Clock property, you could attach onto the CurrentTimeInvalidated event and watch for the time to hit 1.5 seconds. The event has a lot of precision (i.e. it gets raised VERY often) so you don't want to do too much in response to the event unless you have to.

i resolved the problem... :) :) ....
i decide make me own application with many ideas that had taken of other forums.
My solution was easier than i planned, i used 2 videos, 2 mediaElements, a mediaEnded event and boolean variable to chage the video....
and works perfectly! Solution are here ------> (Solution, and coments)
in my app, i didn't have to use properties like clocks, TimeLines, DispatcherTimer, or any event like a CurrentTimeInvalidate, i just used the MediaEnded event and a boolean variable. :) no more. i have 2 videos (1,5 seconds and 3 seconds). when MediaEnded(media 1,5 seconds) mediaElement1,5sec.Position = TimeSpam.Zero; and MediElement3sec.Position = TimeSpam.Zero, and when i clicked the button, i just evaluated the variable (boolean) and play complet video of 3 seconds.
however, the source code are here: MainWindow.xaml
<Window x:Class="wpf_TestVideos.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="371" Width="525" Loaded="Window_Loaded">
<Grid>
<MediaElement Height="268" HorizontalAlignment="Left" Margin="141,12,0,0" Name="mediaElement15sec" VerticalAlignment="Top" Width="237" MediaEnded="mediaElement15sec_MediaEnded" />
<MediaElement Height="268" HorizontalAlignment="Left" Margin="142,12,0,0" Name="mediaElement3sec" VerticalAlignment="Top" Width="236" />
<Button Content="Load" Height="34" HorizontalAlignment="Left" Margin="12,286,0,0" Name="btLoad" VerticalAlignment="Top" Width="73" Click="btLoad_Click" />
<Button Content="Inicio Juego" Height="23" HorizontalAlignment="Left" Margin="128,286,0,0" Name="btStart" VerticalAlignment="Top" Width="86" Click="btStart_Click" />
<Button Content=""Reconoce Gesto"" Height="23" HorizontalAlignment="Left" Margin="285,286,0,0" Name="btGesture" VerticalAlignment="Top" Width="108" Click="btGesture_Click" />
</Grid>
MainWindow.xaml.cs:
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Navigation;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Interop;
using System.Windows.Media.Animation;
using System.Threading;
namespace wpf_TestVideos
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
string VideoLocation = System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath);
string sFileName = "";
string sFileName2 = "";
bool bVideoLoop = true;
TranslateTransform trans = new TranslateTransform();
private void btLoad_Click(object sender, RoutedEventArgs e)
{
mediaElement15sec.LoadedBehavior = MediaState.Manual;
mediaElement3sec.LoadedBehavior = MediaState.Manual;
btGesture.IsEnabled = true;
btStart.IsEnabled = true;
btLoad.IsEnabled = false;
DirectoryInfo df = new DirectoryInfo(VideoLocation);
if (df.Exists)
{
sFileName = VideoLocation + #"\Krown_test_loop.mov";
mediaElement15sec.Source = new Uri(sFileName);
mediaElement15sec.Stretch = Stretch.Fill;
sFileName2 = VideoLocation + #"\Krown_test_7.mov";
mediaElement3sec.Source = new Uri(sFileName2);
mediaElement3sec.Stretch = Stretch.Fill;
}
else
{
System.Windows.Forms.MessageBox.Show("No se puede cargar el video", "TestAll");
}
}
private void btStart_Click(object sender, RoutedEventArgs e)
{
mediaElement15sec.Position = TimeSpan.Zero;
mediaElement3sec.Position = TimeSpan.Zero;
mediaElement15sec.Play();
mediaElement3sec.Play();
bVideoLoop = true;
//VisualStateManager.GoToState(mediaElement15sec, "Bring1,5ToFront", true);
}
private void mediaElement15sec_MediaEnded(object sender, RoutedEventArgs e)
{
if (bVideoLoop)
{
mediaElement15sec.Position = TimeSpan.Zero;
mediaElement3sec.Position = TimeSpan.Zero;
}
}
private void btGesture_Click(object sender, RoutedEventArgs e)
{
bVideoLoop = false;
//Animacion_Opacidad(bVideoLoop);
//VisualStateManager.GoToState(mediaElement3sec, "Bring300ToFront", true);
}
private void Animacion_Opacidad(bool bLoop)
{
mediaElement15sec.RenderTransform = trans;
if (!bLoop)
{
DoubleAnimation anim1 = new DoubleAnimation(1, 0, TimeSpan.FromSeconds(1));
trans.BeginAnimation(OpacityProperty, anim1);
}
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
btGesture.IsEnabled = false;
btStart.IsEnabled = false;
btLoad.IsEnabled = true;
}
}
}

The accepted solution seems to be more a workaround than a solution.. what in case once you will need to use not 1.5 but another time, eg. 2.5 seconds? will you have to change the videos? The solution could be using a DistpatcherTimer:
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(1.5); // your time
timer.Tick += timer_Tick;
timer.Start();
mePlayer.Play(); // run timer and player at same time
When the timer_Tick is reached just set the position to zero and call Play() again:
void timer_Tick(object sender, EventArgs e)
{
mePlayer.Position = new TimeSpan(0, 0, 0, 0);
mePlayer.Play();
}
And when clicking the second button, detach the timer (... can be attached later when necessary):
timer.Tick -= timer_Tick;

Related

Attach Mouse Events to Rect WPF

I have the following program that creates Rectangle using Rect object. I want to attach Mouse events to newly created Rect. How can I do that? Please help. Here's the code below.
XAML
<Window x:Class="TestDrawing.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:TestDrawing"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid Margin="12">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<Canvas>
<Button x:Name="BtnAddRectangle" Content="Add Rectngle" Click="BtnAddRectangle_Click" Height="20"/>
</Canvas>
</StackPanel>
<Canvas Name="canvas">
</Canvas>
</Grid>
CS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace TestDrawing
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
bool drag = false;
Point startPoint;
public MainWindow()
{
InitializeComponent();
}
// this creates and adds rectangles dynamically
private void BtnAddRectangle_Click(object sender, RoutedEventArgs e)
{
DrawingVisual drawingVisual = new DrawingVisual();
// Retrieve the DrawingContext in order to create new drawing content.
DrawingContext drawingContext = drawingVisual.RenderOpen();
// Create a rectangle and draw it in the DrawingContext.
Rect rect = new Rect(new Size(150, 100));
drawingContext.DrawRectangle(Brushes.LightBlue, null,rect);
drawingContext.Close();
canvas.Children.Add(new VisualHost { Visual = drawingVisual });
foreach (UIElement child in canvas.Children)
{
//Not working
child.MouseDown += rectangle_MouseDown;
child.MouseMove += rectangle_MouseMove;
}
}
private void rectangle_MouseDown(object sender, MouseButtonEventArgs e)
{
// start dragging
drag = true;
// save start point of dragging
startPoint = Mouse.GetPosition(canvas);
}
private void rectangle_MouseMove(object sender, MouseEventArgs e)
{
// if dragging, then adjust rectangle position based on mouse movement
if (drag)
{
Rectangle draggedRectangle = sender as Rectangle;
Point newPoint = Mouse.GetPosition(canvas);
double left = Canvas.GetLeft(draggedRectangle);
double top = Canvas.GetTop(draggedRectangle);
Canvas.SetLeft(draggedRectangle, left + (newPoint.X - startPoint.X));
Canvas.SetTop(draggedRectangle, top + (newPoint.Y - startPoint.Y));
startPoint = newPoint;
}
}
private void rectangle_MouseUp(object sender, MouseButtonEventArgs e)
{
// stop dragging
drag = false;
}
}
public class VisualHost : UIElement
{
public Visual Visual { get; set; }
protected override int VisualChildrenCount
{
get { return Visual != null ? 1 : 0; }
}
protected override Visual GetVisualChild(int index)
{
return Visual;
}
}
}
Here's a quote from the MSDN page on Using DrawingVisual Objects:
The DrawingVisual is a lightweight drawing class that is used to render shapes, images, or text. This class is considered lightweight because it does not provide layout or event handling, which improves its performance. For this reason, drawings are ideal for backgrounds and clip art.
If you need event handling, why not just use the existing Rectangle class? Your existing code can be easily changed to use this class instead of your custom VisualHost.
private void BtnAddRectangle_Click(object sender, RoutedEventArgs e)
{
Rectangle rect = new Rectangle() { Fill = Brushes.LightBlue, Width = 150, Height = 100 };
canvas.Children.Add(rect);
foreach (UIElement child in canvas.Children)
{
child.MouseDown += rectangle_MouseDown;
child.MouseMove += rectangle_MouseMove;
}
}

Argument 2:cannot convert from string to int visual studio 2017 c# wpf app

I'm trying to learn C# programming from a book and the code I have been taught to enter so far is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace SaveTheHumans
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
Random random = new Random();
public MainWindow()
{
InitializeComponent();
}
private void startButton_Click(object sender, RoutedEventArgs e)
{
AddEnemy();
}
private void AddEnemy()
{
ContentControl enemy = new ContentControl();
enemy.Template = Resources["EnemyTemplate"] as ControlTemplate;
AnimateEnemy(enemy, 0, playArea.ActualWidth - 100, "(Canvas.Left)");
AnimateEnemy(enemy, random.Next((int)playArea.ActualHeight - 100));
random.Next((int) playArea.ActualHeight - 100, "(Canvas.Top");
playArea.Children.Add(enemy);
}
private void AnimateEnemy(ContentControl enemy, int v)
{
throw new NotImplementedException();
}
private void AnimateEnemy(ContentControl enemy, double from, double to, string propertyToAnimate)
{
Storyboard storyboard = new Storyboard() { AutoReverse = true, RepeatBehavior = RepeatBehavior.Forever };
DoubleAnimation animation = new DoubleAnimation()
{
From = from,
To = to,
Duration = new Duration(TimeSpan.FromSeconds(random.Next(4, 6))),
};
Storyboard.SetTarget(animation, enemy);
Storyboard.SetTargetProperty(animation, new PropertyPath(propertyToAnimate));
storyboard.Children.Add(animation);
storyboard.Begin();
}
}
}
It is intended to be a game and the code is setting where enemies can spawn and move around in once the start button is clicked. I've tried searching other posts for problems but none of them have fixed my error. The book in question if it would be of any help is Head First C#
the particular line causing this error is this:
random.Next((int) playArea.ActualHeight - 100, "(Canvas.Top");
any help would be much appreciated
The Next method expects two int as parameters so you need to define "(Canvas.Top" as int to call the method like :
random.Next((int) playArea.ActualHeight - 100, (int) playArea.MaxHeight);

There is no argument given that corresponds to the required formal parameter 'sender' of MainWindow

I'm totally new to programming. I'm currently trying to create the WPF App that will calculate the Square Root etc. of the number1. I have a problem with using a method that calculates the square root (and not only). I got an error saying:
There is no argument given that corresponds to the required formal parameter 'sender' of 'MainWindow.RadioBT_Root2_Checked(object, RoutedEventArgs)'
This error occurs on RadioBT_Root3_Checked and RadioBT_Root4_Checked, because I've got 3 methods.
Its code is CS7036. What am i doing bad? I was searching so much but I can't find it (or I can't search).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Examples {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow: Window {
public MainWindow() {
InitializeComponent();
}
double number1;
double number2;
double result;
private void TXB_1_TextChanged(object sender, TextChangedEventArgs e) {
}
private void TXB_2_TextChanged(object sender, TextChangedEventArgs e) {
}
private void BT_Potegowanie_Click(object sender, RoutedEventArgs e) {
try {
number1 = double.Parse(TXB_1.Text);
number2 = double.Parse(TXB_2.Text);
result = Math.Pow(number1, number2);
MessageBox.Show("WYNIK: " + result.ToString());
} catch (Exception) {
MessageBox.Show("Wystąpił błąd.", "Błąd", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public void BT_Root_Click(object sender, RoutedEventArgs e) {
if (RadioBT_Root2_Checked()) ///CS7036
MessageBox.Show("RESULT: " + result.ToString());
if (RadioBT_Root3_Checked()) ///CS7036
MessageBox.Show("RESULT: " + result.ToString());
if (RadioBT_Root4_Checked()) ///CS7036
MessageBox.Show("RESULT: " + result.ToString());
}
public void RadioBT_Root2_Checked(object sender, RoutedEventArgs e) {
number1 = double.Parse(TXB_1.Text);
result = Math.Sqrt(number1);
}
public void RadioBT_Root3_Checked(object sender, RoutedEventArgs e) {
number1 = double.Parse(TXB_1.Text);
number2 = (1 / 3.0);
result = Math.Pow(number1, number2);
}
public void RadioBT_Root4_Checked(object sender, RoutedEventArgs e) {
number1 = double.Parse(TXB_1.Text);
number2 = (1 / 4.0);
result = Math.Pow(number1, number2);
}
}
}
EDIT: I've done what Ed Plunkett sugested and I've now another problem. It's XAML related (I think). I also found that i might need place '?? false' in some places. The error list says: 'MainWindow' does not contain a definition for 'RadioBT_Root4_Checked' and no extension method 'RadioBT_Root4_Checked' accepting a first argument of type 'MainWindow' could be found (are you missing a using directive or an assembly reference?)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Examples
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void TXB_1_TextChanged(object sender, TextChan`enter code here`gedEventArgs e)
{
}
private void TXB_2_TextChanged(object sender, TextChangedEventArgs e)
{
}
public void BT_Root_Click(object sender, RoutedEventArgs e)
{
double number1 = 0;
double number2 = 0;
double result = 0;
if (RadioBT_Root2.IsChecked ?? false) ///CS0266
{
number1 = double.Parse(TXB_1.Text);
result = Math.Sqrt(number1);
}
else if (RadioBT_Root3.IsChecked ?? false) ///CS0266
{
number1 = double.Parse(TXB_1.Text);
number2 = (1 / 3.0);
result = Math.Pow(number1, number2);
}
else if (RadioBT_Root4.IsChecked ?? false) ///CS0266
{
number1 = double.Parse(TXB_1.Text);
number2 = (1 / 4.0);
result = Math.Pow(number1, number2);
}
MessageBox.Show("RESULT: " + result.ToString());
}
}
My XAML code:
<Window x:Class="Examples.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:Examples"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Label x:Name="label" Content="First number
First number" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,10,0,0" Width="117" Height="31" FontSize="15"/>
<TextBox x:Name="TXB_1" HorizontalAlignment="Left" Height="28" Margin="132,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" FontSize="15" TextChanged="TXB_1_TextChanged"/>
<Label x:Name="label1" Content="Second number
Second number
" HorizontalAlignment="Left" Margin="10,46,0,0" VerticalAlignment="Top" Width="117" Height="30" FontSize="15"/>
<TextBox x:Name="TXB_2" HorizontalAlignment="Left" Height="28" Margin="132,48,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" TextChanged="TXB_2_TextChanged" FontSize="15"/>
<Separator HorizontalAlignment="Left" Height="19" Margin="0,69,0,0" VerticalAlignment="Top" Width="517"/>
<Button x:Name="BT_Root" Content="ROOT" HorizontalAlignment="Left" Margin="10,81,0,0" VerticalAlignment="Top" Width="128" Height="48" FontSize="16" Click="BT_Root_Click"/>
<RadioButton x:Name="RadioBT_Root2" Content="Root2" HorizontalAlignment="Left" Margin="143,81,0,0" VerticalAlignment="Top" Checked="RadioBT_Root2_Checked"/>
<RadioButton x:Name="RadioBT_Root3" Content="Root3" HorizontalAlignment="Left" Margin="143,96,0,0" VerticalAlignment="Top" Checked="RadioBT_Root3_Checked"/>
<RadioButton x:Name="RadioBT_Root4" Content="Root4" HorizontalAlignment="Left" Margin="143,111,0,0" VerticalAlignment="Top" Checked="RadioBT_Root4_Checked"/>
</Grid>
</Window>
I aslo tried changing 'Checked="RadioBT_Root4_Checked"/>' to 'Checked="RadioBT_Root4.IsChecked"/>'. It says 'Error Checked="RadioBT_Root2.IsChecked" is not valid. 'RadioBT_Root2.IsChecked' is not a valid event handler method name. Only instance methods on the generated or code-behind class are valid.'
You're calling your event handlers -- for example, RadioBT_Root2_Checked -- with no parameters, even though they require two parameters. You're also acting like they "return" bool, even though they "return" nothing.
What does "return" mean? 1 + 3 returns 4:
int x = 1 + 3;
Now x is equal to 4.
Functions can return values:
public bool GreaterThan(int x, int y) { return x > y; }
Use it like this:
if (GreaterThan(10, 9))
{
MessageBox.Show("10 is greater than 9");
}
But I think you don't really want to call those methods. I think this is what you want:
When Root is clicked, I think you want to find out which checkbox the user clicked, and then show that result. The results are calculated when the checkboxes are checked; those functions are the event handlers. To find out IF each checkbox is checked, look at the checkbox object -- using the name you gave it -- and look at its IsChecked property.
Like so:
public void BT_Root_Click(object sender, RoutedEventArgs e)
{
if (RadioBT_Root2.IsChecked)
MessageBox.Show("RESULT: " + result.ToString());
else if (RadioBT_Root3.IsChecked)
MessageBox.Show("RESULT: " + result.ToString());
else if (RadioBT_Root4.IsChecked)
MessageBox.Show("RESULT: " + result.ToString());
}
Except, look at those if statements: All three are doing the same thing. You can simplify further:
public void BT_Root_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("RESULT: " + result.ToString());
}
But here's a better way:
public void BT_Root_Click(object sender, RoutedEventArgs e)
{
double number1 = 0;
double number2 = 0;
double result = 0;
if (RadioBT_Root2.IsChecked)
{
number1 = double.Parse(TXB_1.Text);
result = Math.Sqrt(number1);
}
else if (RadioBT_Root3.IsChecked)
{
number1 = double.Parse(TXB_1.Text);
number2 = (1 / 3.0);
result = Math.Pow(number1, number2);
}
else if (RadioBT_Root4.IsChecked)
{
number1 = double.Parse(TXB_1.Text);
number2 = (1 / 4.0);
result = Math.Pow(number1, number2);
}
MessageBox.Show("RESULT: " + result.ToString());
}
You don't need result, number, and number2 to be class members, and you don't need those *_Checked event handlers at all.

Refreshing canvas

I have a question about refreshing canvas. There is .Refresh() or .Clear() in WinForms.But what about WPF?
I watched some methods how to do it, but it didn't help me at all.
The situation is that my canvas contains textBox and Button. When I click button I can draw some ellipses.
And I need to clear these ellipses after my every click on button but without clearing textBox and Button from this Canvas!
My WPF Xaml:
<Window x:Class="draw.CreateEllipse"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Create" Height="768" Width="1024" WindowStartupLocation="CenterScreen" Name="Create" Closed="Create_Closed">
<Canvas Name="can" Background="White" MouseDown="can_MouseDown">
<TextBox Name="txbNumber" Height="34" Canvas.Left="797" TextWrapping="Wrap" Text="5" Canvas.Top="76" Width="209" FontSize="18"/>
<Button Name="btnCreate" Content="Create" Canvas.Left="797" Canvas.Top="130" Width="209" Height="66" FontSize="18" Click="btnCreate_Click"/>
</Canvas>
My C# :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace draw
{
/// <summary>
/// Логика взаимодействия для CreateGraph.xaml
/// </summary>
public partial class Create : Window
{
public Create()
{
InitializeComponent();
}
int n, i;
Ellipse[] v;
Rectangle rect = new Rectangle();
SolidColorBrush solidcolor = new SolidColorBrush();
private void btnCreate_Click(object sender, RoutedEventArgs e)
{
n = Convert.ToInt16(txbNumber.Text);
v = new Ellipse[n];
//can.Children.Clear();
}
private void Create_Closed(object sender, EventArgs e)
{
Application.Current.Shutdown();
}
private void can_MouseDown(object sender, MouseButtonEventArgs e)
{
solidcolor.Color = Colors.Transparent;
//Ellipse myEllipse = new Ellipse();
SolidColorBrush mySolidColorBrush = new SolidColorBrush();
for (i = 0; i < n; i++)
{
v[i] = new Ellipse();
mySolidColorBrush.Color = Colors.Transparent;
v[i].Fill = mySolidColorBrush;
v[i].StrokeThickness = 2;
v[i].Stroke = Brushes.Black;
v[i].Width = 75;
v[i].Height = 75;
v[i].Margin = new Thickness(e.GetPosition(can).X, e.GetPosition(can).Y, 0, 0);
can.Children.Add(v[i]);
}
if (n <= 0)
return;
n--;
}
}
}
you can separate your elements with this code:
var can2 = can.Children.OfType<Ellipse>();
above code select all of Ellipses in your Canvas "can".
and you can remove them from your Canvas Like this:
foreach (var element in can2)
{
can.Children.Remove(element);
}
Now you have no ellipse in your Canvas.
Hope this helps you.

Report download progress to user interface

I am working on a project that extracts YouTube videos' audio and saves them to your computer.
To do this, I used a library from GitHub called YouTubeExtractor.
I am using a backgroundworker in order to make the UI usable while the file is being downloaded. This is the code I have so far.
public partial class MainWindow : Window
{
private readonly BackgroundWorker worker = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
worker.DoWork += worker_DoWork;
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
}
private void downloadButton_Click(object sender, RoutedEventArgs e)
{
worker.RunWorkerAsync();
}
string link;
double percentage;
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
this.Dispatcher.Invoke((Action)(() =>
{
link = videoURL.Text;
}));
/*
* Get the available video formats.
* We'll work with them in the video and audio download examples.
*/
IEnumerable<VideoInfo> videoInfos = DownloadUrlResolver.GetDownloadUrls(link);
/*
* We want the first extractable video with the highest audio quality.
*/
VideoInfo video = videoInfos
.Where(info => info.CanExtractAudio)
.OrderByDescending(info => info.AudioBitrate)
.First();
/*
* If the video has a decrypted signature, decipher it
*/
if (video.RequiresDecryption)
{
DownloadUrlResolver.DecryptDownloadUrl(video);
}
/*
* Create the audio downloader.
* The first argument is the video where the audio should be extracted from.
* The second argument is the path to save the audio file.
*/
var audioDownloader = new AudioDownloader(video, System.IO.Path.Combine("C:/Downloads", video.Title + video.AudioExtension));
// Register the progress events. We treat the download progress as 85% of the progress and the extraction progress only as 15% of the progress,
// because the download will take much longer than the audio extraction.
audioDownloader.DownloadProgressChanged += (send, args) => Console.WriteLine(args.ProgressPercentage * 0.85);
audioDownloader.AudioExtractionProgressChanged += (send, args) => Console.WriteLine(85 + args.ProgressPercentage * 0.15);
/*
* Execute the audio downloader.
* For GUI applications note, that this method runs synchronously.
*/
audioDownloader.Execute();
}
}
}
The problem I have is that I want to display this
audioDownloader.DownloadProgressChanged += (send, args) => Console.WriteLine(args.ProgressPercentage * 0.85);
audioDownloader.AudioExtractionProgressChanged += (send, args) => Console.WriteLine(85 + args.ProgressPercentage * 0.15);
In a UI element like a label or a progressbar instead of Console.WriteLine
Whenever I do label1.Text = (85 + args.ProgressPercentage * 0.15); It throws me a an error like
" The calling thread cannot access this object because a different thread owns it."
I know you can do solve this with a delegate, I need a clear instruction on how so.
Thank you.
Here's a modern approach for doing this using Tasks and async / await keywords
Plus the usage of Dispatcher.BeginInvoke for updating your UI.
Code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using YoutubeExtractor;
namespace WpfApplication1
{
public partial class MainWindow
{
public MainWindow() {
InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e) {
string videoUrl = #"https://www.youtube.com/watch?v=5aXsrYI3S6g";
await DownloadVideoAsync(videoUrl);
}
private Task DownloadVideoAsync(string url) {
return Task.Run(() => {
IEnumerable<VideoInfo> videoInfos = DownloadUrlResolver.GetDownloadUrls(url);
VideoInfo videoInfo = videoInfos.FirstOrDefault();
if (videoInfo != null) {
if (videoInfo.RequiresDecryption) {
DownloadUrlResolver.DecryptDownloadUrl(videoInfo);
}
string savePath =
Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
Path.ChangeExtension("myVideo", videoInfo.VideoExtension));
var downloader = new VideoDownloader(videoInfo, savePath);
downloader.DownloadProgressChanged += downloader_DownloadProgressChanged;
downloader.Execute();
}
});
}
private void downloader_DownloadProgressChanged(object sender, ProgressEventArgs e) {
Dispatcher.BeginInvoke((Action) (() => {
double progressPercentage = e.ProgressPercentage;
ProgressBar1.Value = progressPercentage;
TextBox1.Text = string.Format("{0:F} %", progressPercentage);
}));
}
}
}
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"
Width="525"
Height="350">
<Grid>
<StackPanel>
<Button Click="Button_Click" Content="Download" />
<ProgressBar x:Name="ProgressBar1"
Height="20"
Maximum="100" />
<TextBox x:Name="TextBox1" />
</StackPanel>
</Grid>
</Window>

Categories