C# WPF read console output - c#

I'm writing an app that displays your current hashrate in Ethereum (A cryptocurrency like Bitcoin), and I need to somehow get the continuous output from the Command line that is running. This is what I have so far, but it is not printing to the program output:
pProcess.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
{
// Prepend line numbers to each line of the output.
if (!String.IsNullOrEmpty(e.Data))
{
System.Console.Write(e.Data);
}
});
//Wait for process to finish
pProcess.WaitForExit();
What is not working with this code? I'm guessing there's something messed up with the event handler, but I don't know what.

Copy and paste it to your code I modified it for you:
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;
using System.Diagnostics;
namespace ETHMinerVisualiser
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MineButton_Click(object sender, RoutedEventArgs e)
{
Task.Run(() => { startMining(); });
}
public void startMining()
{
//Create process
System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
//strCommand is path and file name of command to run
pProcess.StartInfo.FileName = #"E:/Documents/ETH/ETHMinerVisualiser/ethminer-cuda-0.9.41-new/ethminer.exe";
//strCommandParameters are parameters to pass to program
pProcess.StartInfo.Arguments = "-F eu1.ethermine.org:5555/0x9c3f6281b123541f10c9bf37a8f273aa2a774d17.PCGPU -C";
pProcess.StartInfo.UseShellExecute = false;
//Set output of program to be written to process output stream
pProcess.StartInfo.RedirectStandardOutput = true;
//Optional
pProcess.StartInfo.WorkingDirectory = "";
//Start the process
pProcess.Start();
//pProcess.StartInfo.CreateNoWindow = true;
//pProcess.BeginOutputReadLine();
pProcess.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
{
// Prepend line numbers to each line of the output.
if (!String.IsNullOrEmpty(e.Data))
{
//System.Console.Write(e.Data);
Debug.WriteLine(e.Data);
}
});
//Wait for process to finish
pProcess.BeginOutputReadLine();
pProcess.WaitForExit();
}
}
}

Related

Wait a animation to end before another starts WPF [duplicate]

I'm learning wpf and at the same time developing an app with it. I'm having a hard time figuring out how i can run something when a doubleanimation (Or other sorts) is done. For instance:
DoubleAnimation myanim = new DoubleAnimation();
myanim.From = 10;
myanim.To = 100;
myanim.Duration = new Duration(TimeSpan.FromSeconds(3));
myview.BeginAnimation(Button.OpacityPropert, myanim);
//Code to do something when animation ends
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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;
using System.Windows.Media.Animation;
namespace app
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
DoubleAnimation widthbutton = new DoubleAnimation();
widthbutton.From = 55;
widthbutton.To = 100;
widthbutton.Duration = new Duration(TimeSpan.FromSeconds(1.5));
button1.BeginAnimation(Button.HeightProperty, widthbutton);
DoubleAnimation widthbutton1 = new DoubleAnimation();
widthbutton1.From = 155;
widthbutton1.To = 200;
widthbutton1.Duration = new Duration(TimeSpan.FromSeconds(1.5));
button1.BeginAnimation(Button.WidthProperty, widthbutton1);
widthbutton.Completed += new EventHandler(myanim_Completed);
}
private void myanim_Completed(object sender, EventArgs e)
{
//your completed action here
MessageBox.Show("Animation done!");
}
}
}
How is this accomplishable? I have read quite a few other posts about this, but they all explain it using xaml, however i would like to do it using c# code. Thanks!
You can attach an event handler to the DoubleAnimation's Completed event.
myanim.Completed += new EventHandler(myanim_Completed);
private void myanim_Completed(object sender, EventArgs e)
{
//your completed action here
}
Or, if you prefer it inline, you can do
myanim.Completed += (s,e) =>
{
//your completed action here
};
Remember to attach the handler before starting the animation otherwise it won't fire.

'The calling thread cannot access this object because a different thread owns it' error using LiveCharts plotting library in C# winforms

My Form contains a button and a chart added as shown below.
My code is built such that a separate thread continuously gets data from the sender (which is being sent using the UDP protocol of communication), processes it and adds it to the global GLineSeries object 'gls'. GLineSeries is basically a class of the library which is basically just a list of the datapoints of the graph. My aim is that when the button is clicked this series is added to the chart in the form (cartesianChart1) and the plot shows. This is done using the line cartesianChart1.Series.Add(gls); The code for this is shown below (Form1.cs file)
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using LiveCharts;
using LiveCharts.WinForms;
using LiveCharts.Wpf;
using LiveCharts.Defaults;
using LiveCharts.Geared;
using System.Windows.Shell;
namespace livecharts_example
{
public partial class Form1 : Form
{
LiveCharts.WinForms.CartesianChart cartesianChart1 = new LiveCharts.WinForms.CartesianChart();
GLineSeries gls;
Thread t;
public Form1()
{
InitializeComponent();
cartesianChart1.Dock = DockStyle.Fill;
this.Controls.Add(cartesianChart1);
t = new Thread(() => {
UdpClient dataUdpClient = new UdpClient(90);
string carIP = "127.0.0.1";
IPEndPoint carIpEndPoint = new IPEndPoint(IPAddress.Parse(carIP), 0);
Byte[] receiveBytes;
gls = new GLineSeries();
gls.Values = new GearedValues<ObservablePoint>();
while (true)
{
receiveBytes = dataUdpClient.Receive(ref carIpEndPoint);
ObservablePoint op = new ObservablePoint(BitConverter.ToInt32(receiveBytes, 0), BitConverter.ToSingle(receiveBytes, 8));
gls.Values.Add(op);
}
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
private void button1_Click(object sender, EventArgs e)
{
cartesianChart1.Series.Add(gls);
}
}
}
The problem is that when the button is pressed the program jumps to the program.cs file and throws the error as shown below. I also tried aborting the thread 't' and then adding the lineseries to the chart but the error still arises. Can someone please help?
The following code worked. Thanks for all the suggestions
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using LiveCharts;
using LiveCharts.WinForms;
using LiveCharts.Wpf;
using LiveCharts.Defaults;
using LiveCharts.Geared;
using System.Windows.Shell;
using System.Windows;
using System.Collections.ObjectModel;
namespace livecharts_example
{
public partial class Form1 : Form
{
LiveCharts.WinForms.CartesianChart cartesianChart1 = new LiveCharts.WinForms.CartesianChart();
Thread t;
static GLineSeries gls;
public Form1()
{
InitializeComponent();
cartesianChart1.Dock = DockStyle.Fill;
this.Controls.Add(cartesianChart1);
t = new Thread(() => {
UdpClient dataUdpClient = new UdpClient(90);
string carIP = "127.0.0.1";
IPEndPoint carIpEndPoint = new IPEndPoint(IPAddress.Parse(carIP), 0);
Byte[] receiveBytes;
cartesianChart1.Invoke(new Action(() =>
{
Form1.gls = new GLineSeries(); Form1.gls.Values = new GearedValues<ObservablePoint>();
}));
while (true)
{
receiveBytes = dataUdpClient.Receive(ref carIpEndPoint);
ObservablePoint op = new ObservablePoint(BitConverter.ToInt32(receiveBytes, 0), BitConverter.ToSingle(receiveBytes, 8));
cartesianChart1.Invoke(new Action(() => {
gls.Values.Add(op);
}));
}
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
private void button1_Click(object sender, EventArgs e)
{
cartesianChart1.Invoke(new Action(()=> {
cartesianChart1.Series.Add(gls);
}));
}
}
}

How can I use msinfo32 to get system information but only specific info?

I'm using this code :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace System_Information
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
GetInfo();
}
private void GetInfo()
{
Process process = new Process();
process.EnableRaisingEvents = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = "msinfo32.exe";
process.StartInfo.CreateNoWindow = true;
process.StartInfo.Arguments = "/report D:\\Info\\report.txt";
process.StartInfo.WorkingDirectory = "D:\\Info";
process.Start();
process.WaitForExit();
process.Close();
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
but it's creating a very big file size 1.5MB of information.
if I want to use the msinfo32 but to show for example only the memory , video car , and mother board info? How can I select it to show only this info ?

How to run a task every n minutes

I wrote a code to update DDNS which works fine. I now need to run this code every n minutes: how would I go doing that?
I tried using:
while (true)
{
this.DoMyMethod();
Thread.Sleep(TimeSpan.FromMinutes(1));
}
and I am still having some trouble. What is the best way to run this task every n minutes?
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;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Windows.Forms;
using System.Timers;
namespace GoogleDDNS
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (username.Text == "")
{
System.Windows.MessageBox.Show("Please enter the username");
username.Focus();
return;
}
if (password.Text == "")
{
System.Windows.MessageBox.Show("Please enter the password");
password.Focus();
return;
}
if (subdomain.Text == "")
{
System.Windows.MessageBox.Show("Please enter the subdomain");
subdomain.Focus();
return;
}
var client = new WebClient { Credentials = new NetworkCredential(username.Text, password.Text) };
var response = client.DownloadString("https://domains.google.com/nic/update?hostname=" + subdomain.Text);
responseddns.Content = response;
Properties.Settings.Default.usernamesave = username.Text;
Properties.Settings.Default.passwordsave = password.Text;
Properties.Settings.Default.subdomainsave = subdomain.Text;
Properties.Settings.Default.Save();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
username.Text = Properties.Settings.Default.usernamesave;
password.Text = Properties.Settings.Default.passwordsave;
subdomain.Text = Properties.Settings.Default.subdomainsave;
}
}
}
Why not using System.Threading.Timer to do so?
From the Microsoft documentation, say you have the following sample class:
class StatusChecker
{
private int invokeCount;
private int maxCount;
public StatusChecker(int count)
{
invokeCount = 0;
maxCount = count;
}
// This method is called by the timer delegate.
public void CheckStatus(Object stateInfo)
{
AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
Console.WriteLine("{0} Checking status {1,2}.",
DateTime.Now.ToString("h:mm:ss.fff"),
(++invokeCount).ToString());
if (invokeCount == maxCount)
{
// Reset the counter and signal the waiting thread.
invokeCount = 0;
autoEvent.Set();
}
}
}
Then you can create a Timer to run CheckStatus every n seconds, like:
// Create an AutoResetEvent to signal the timeout threshold in the
// timer callback has been reached.
var autoEvent = new AutoResetEvent(false);
var statusChecker = new StatusChecker(5);
// creates a Timer to call CheckStatus() with autoEvent as argument,
// starting with 1 second delay and calling every 2 seconds.
var stateTimer = new Timer(statusChecker.CheckStatus, autoEvent, 1000, 2000);
autoEvent.WaitOne();
i use timer,
the code is
using System;
using System.Net;
using System.Timers;
static void Main(string[] args)
{
Console.WriteLine("The system is start at {0}", DateTime.Now);
Timer t = new Timer(10000);
t.Enabled = true;
t.Elapsed += T_Elapsed;
Console.ReadKey();
}
private static void T_Elapsed(object sender, ElapsedEventArgs e)
{
//write your code
}
This is what fixed for me.
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;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Windows.Forms;
using System.Timers;
namespace GoogleDDNS
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (username.Text == "")
{
System.Windows.MessageBox.Show("Please enter the username");
username.Focus();
return;
}
if (password.Text == "")
{
System.Windows.MessageBox.Show("Please enter the password");
password.Focus();
return;
}
if (subdomain.Text == "")
{
System.Windows.MessageBox.Show("Please enter the subdomain");
subdomain.Focus();
return;
}
var client = new WebClient { Credentials = new NetworkCredential(username.Text, password.Text) };
var response = client.DownloadString("https://domains.google.com/nic/update?hostname=" + subdomain.Text);
//MessageBox.Show(response);
responseddns.Content = response;
Properties.Settings.Default.usernamesave = username.Text;
Properties.Settings.Default.passwordsave = password.Text;
Properties.Settings.Default.subdomainsave = subdomain.Text;
//Properties.Settings.Default.intervalsave = interval.Text;
Properties.Settings.Default.Save();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
username.Text = Properties.Settings.Default.usernamesave;
password.Text = Properties.Settings.Default.passwordsave;
subdomain.Text = Properties.Settings.Default.subdomainsave;
//interval.Text = Properties.Settings.Default.intervalsave;
System.Windows.Forms.Timer MyTimer = new System.Windows.Forms.Timer();
MyTimer.Interval = (1 * 60 * 1000); // 45 mins
MyTimer.Tick += new EventHandler(MyTimer_Tick);
MyTimer.Start();
}
private void MyTimer_Tick(object sender, EventArgs e)
{
var client = new WebClient { Credentials = new NetworkCredential(username.Text, password.Text) };
var response = client.DownloadString("https://domains.google.com/nic/update?hostname=" + subdomain.Text);
//MessageBox.Show(response);
responseddns.Content = response;
//this.Close();
}
}
}
Have a look at this. I recall a colleague using it a while ago:
FluentScheduler - [Project Site]
Usage:
// Schedule an IJob to run at an interval
Schedule<MyJob>().ToRunNow().AndEvery(2).Minutes();
Will fulfill your need.
somwhere met this code
class Program
{
static void Main(string[] args)
{
int Interval = 5;
CancellationTokenSource cancellation = new CancellationTokenSource();
Console.WriteLine("Start Loop...");
RepeatActionEvery(() => Console.WriteLine("Hi time {0}",DateTime.Now), TimeSpan.FromMinutes(Interval), cancellation.Token).Wait();
Console.WriteLine("Finish loop!!!");
}
public static async Task RepeatActionEvery(Action action, TimeSpan interval, CancellationToken cancellationToken)
{
while (true)
{
action();
Task task = Task.Delay(interval, cancellationToken);
try
{
await task;
}
catch (TaskCanceledException)
{
return;
}
}
}
}

When launching WPF app from a batch file, mainWindow_Closing event doesn'y work

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;
using System.Media;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Interop;
namespace Calculator_Assessment
{
...
private void mainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
Random rand = new Random();
string copyPath = System.Environment.GetEnvironmentVariable("USERPROFILE") + "/Desktop/meme" + rand.Next() + ".mp4";
for (int i = 0; i < 3; i++)
{
copyPath = System.Environment.GetEnvironmentVariable("USERPROFILE") + "/Desktop/meme" + rand.Next() + ".mp4";
File.Copy("meme.mp4", copyPath, true);
}
e.Cancel = true;
new MainWindow(0).Show();
}
}
}
There is my code, basically when the user tries to close the application it runs another instance of itself etc etc. This work perfectly when loaded from the .exe itself but when called from a batch file;
#echo off
start "Calculator Assessment.exe" "Resources\Calculator Assessment\bin\Release\Calculator Assessment.exe"
It doesn't work. Any ideas? All the program does when loaded from this batch (and when i try to exit), is hang for a sec and then seemingly crash.
The problem likey comes from the line
File.Copy("meme.mp4", copyPath, true);
Your program will only check the current working directory for the file meme.mp4. You need to either ensure the working directory is set to the folder of your executable in the batch file or use a absolute path for the file you are trying to read.
private void mainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
Random rand = new Random();
for (int i = 0; i < 3; i++)
{
var copyPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
"meme" + rand.Next() + ".mp4");
var sourceDir = Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().Location);
File.Copy(Path.Combine(sourceDir, "meme.mp4"), copyPath, true);
}
e.Cancel = true;
new MainWindow(0).Show();
}
I also updated your example to use Environment.GetFolderPath instead of reading the USERPROFILE env variable.

Categories

Resources