Wait users click on popup with Rg.Plugins.Popup - c#

I show a pop up and I have to wait user's choice to put something in an entry control, the problem is that the if statment where I decide what goes as text in entry is executing at the same time as the popup shows.
I tried by making the method await but not working, here's what I have.
Donesn't matter by now the if() statement,I was just trying
This is my popup class (I want to wait until one of the buttons is clicked):
public partial class PopupElegirRFC : PopupPage
{
string sEmisor = "";
string sReceptor = "";
public PopupElegirRFC (string emisor, string receptor)
{
InitializeComponent ();
lblREmisor.Text = "Emisor: " + emisor;
lblRReceptor.Text = "Receptor: " + receptor;
sEmisor = emisor;
sReceptor = receptor;
}
private void BtnEmisor_Clicked(object sender, EventArgs e)
{
PopupNavigation.Instance.PopAllAsync();
VGlobales.sRFSeleccionado = sEmisor;
}
private void BtnReceptor_Clicked(object sender, EventArgs e)
{
PopupNavigation.Instance.PopAllAsync();
VGlobales.sRFSeleccionado = sReceptor;
}
}
This is the code where I want to wait for users choice:
case 2:
await PopupNavigation.Instance.PushAsync(new Popups.PopupElegirRFC(list[0], list[1]));
if (VGlobales.sRFSeleccionado == list[1])
{
RFCavalidar.Text = list[1];
VGlobales.sRFSeleccionado = "";
}
else
{
RFCavalidar.Text = list[0];
VGlobales.sRFSeleccionado = "";
}
break;
The code executes, but it goes directly to the if(), not waiting the user's choice
I would like to the popup to wait until some of both buttons in it is clicked. so I can make the if() validation

It's an old question but my answer can help someone.
Add TaskCompletionSource and wait for return.
Popup class:
public partial class PopupElegirRFC : PopupPage
{
private TaskCompletionSource<string> taskCompletionSource;
public Task<string> PopupClosedTask { get { return taskCompletionSource.Task; } }
string sEmisor = "";
string sReceptor = "";
public PopupElegirRFC (string emisor, string receptor)
{
InitializeComponent();
lblREmisor.Text = "Emisor: " + emisor;
lblRReceptor.Text = "Receptor: " + receptor;
sEmisor = emisor;
sReceptor = receptor;
}
protected override void OnAppearing ()
{
base.OnAppearing();
taskCompletionSource = new TaskCompletionSource<string>();
}
private void BtnEmisor_Clicked (object sender, EventArgs e)
{
taskCompletionSource.SetResult(sEmisor);
PopupNavigation.Instance.PopAllAsync();
}
private void BtnReceptor_Clicked (object sender, EventArgs e)
{
taskCompletionSource.SetResult(sReceptor);
PopupNavigation.Instance.PopAllAsync();
}
}
Code where you want to wait:
var popupElegirRFC = new Popups.PopupElegirRFC(list[0], list[1]);
await PopupNavigation.Instance.PushAsync(popupElegirRFC);
string result = await popupElegirRFC.PopupClosedTask;
if (result == list[1])
{
RFCavalidar.Text = list[1];
}
else
{
RFCavalidar.Text = list[0];
}
This idea came from the link below:
https://github.com/rotorgames/Rg.Plugins.Popup/issues/116

as jason suggested , you can use MessagingCenter to evaluate whether which button is clicked or not.
In your Button click in popup page
private void BtnEmisor_Clicked(object sender, EventArgs e)
{
MessagingCenter.Send((App)Application.Current,"BtnEmisor_Clicked");
PopupNavigation.Instance.PopAllAsync();
VGlobales.sRFSeleccionado = sEmisor;
}
In your non- Popup page
MessagingCenter.Subscribe((App)Application.Current, "BtnEmisor_Clicked", (sender) =>
{
// Do task on that button click
});

Related

Start pause and stop C# method from GUI

I have class method and event
public class DefaultVariables
{
private DataTable SetDataFromSQL()
{
var Eventstatus = new BasicEventsHandlersArgs();
Eventstatus.Status.Task = BasicEventStatus.Busy;
Eventstatus.Status.Task_Status = "Please wait while we performing";
Eventstatus.Status.Task_CurrentProgress = "Verifying Steps...";
Eventstatus.Status.Task_TotalProgress = "Measuring Source Properties , Destinations Properties and someother(s)";
Raise_DefaultVariablesProgressUpdate(Eventstatus);
// Long running SQLs
}
public event EventHandler<BasicEventsHandlersArgs> Event_DefaultVariablesBasciProgress;
protected virtual void Raise_DefaultVariablesProgressUpdate(BasicEventsHandlersArgs e)
{
Event_DefaultVariablesBasciProgress?.Invoke(this, e);
}
}
and I call it in a Windows Forms app like this:
DefaultVariables variables = new DefaultVariables();
public EmployeeTag(string UserID)
{
InitializeComponent();
variables.Event_DefaultVariablesBasciProgress += Variables_Event_DefaultVariablesBasciProgress;
}
private void Variables_Event_DefaultVariablesBasciProgress(object sender, BasicEventsHandlersArgs e)
{
Application.DoEvents();
LabDepartmentCount.Text = e.Status.Task_Status.ToString();
labDesignationCount.Text = e.Status.Task_CurrentProgress.ToString(); ;
labEmCount.Text = e.Status.Task_TotalProgress.ToString();
// while (e.Status.Task != BasicEventStatus.Completed) { importToolStripMenuItem1.Enabled = false; }
if (e.Status.Task == BasicEventStatus.Busy)
{
importToolStripMenuItem1.Enabled = false;
}
if (e.Status.Task == BasicEventStatus.Completed)
{
importToolStripMenuItem1.Enabled = true;
}
}
private void importToolStripMenuItem1_Click(object sender, EventArgs e)
{
SetDataFromSQL();
}
The code is working and raising event as I expected, no error.
I just want to add button on GUI to pause, stop and continue between execution and want to control SetDataFromSQL, pause if there is long running code inside and continue from there.
Just like backgroundworker.cancel() method.
So how can I pause the execution from GUI button?
How can I pass pause flag to wait until I click continue?
Please help me out

Event Handler Fires Twice When Plugging/Unplugging USB Serial Port

I am writing a program which is supposed to detect when a USB serial device is plugged in and then log on to the new com port. The code below works wonderfully, but I have noticed in debugging the code and stepping through it that the event handler "DetectChange" fires twice. I'm not sure that this is normal, or an action of the debugger.
In any case, the code works, but I am new at event handling and I would like to make sure that I am not going to cause any issues as I add more code to actually read and write from the serial port.
(I got some of this code from stackoverflow, but I have misplaced my paper with names for attribution. If you see your code below, my heartfelt thanks.)
using System;
using System.IO.Ports;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Management;
using System.Threading;
namespace SerialTest
{
public partial class Form1 : Form
{
SerialMethods serialMethods = new SerialMethods();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
loadCmdBox();
}
private void CmdBoxPort_SelectedIndexChanged(object sender, EventArgs e)
{
handleComPort();
}
private void handleComPort()
{
// Set the right port for the selected item.
// The portname is based on the "COMx" part of the string (SelectedItem)
string item = CmdBoxPort.SelectedItem.ToString();
// Search for the expression "(COM" in the "selectedItem" string
if (item.Contains("(COM"))
{
// Get the index number where "(COM" starts in the string
int indexOfCom = item.IndexOf("(COM");
// Set PortName to COMx based on the expression in the "selectedItem" string
// It automatically gets the correct length of the COMx expression to make sure
// that also a COM10, COM11 and so on is working properly.
string PortName = item.Substring(indexOfCom + 1, item.Length - indexOfCom - 2);
if (serialMethods._serialPort.IsOpen)
{
serialMethods._serialPort.Close();
serialMethods.Connect(PortName);
label5.Text = "Active Port: " + PortName;
}
else
{
serialMethods.Connect(PortName);
label5.Text = PortName;
}
}
else
return;
}
private void loadCmdBox()
{
// Get all serial (COM)-ports you can see in the devicemanager
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\cimv2",
"SELECT * FROM Win32_PnPEntity WHERE ClassGuid=\"{4d36e978-e325-11ce-bfc1-08002be10318}\"");
// Sort the items in the combobox
CmdBoxPort.Sorted = true;
// Add all available (COM)-ports to the combobox
foreach (System.Management.ManagementObject queryObj in searcher.Get().Cast<ManagementObject>())
{
CmdBoxPort.Items.Add(queryObj["Caption"]);
}
SerialPortService.PortsChanged += (sender1, changedArgs) => DetectChange(changedArgs.EventType);
label2.Text = "";
label3.Text = "";
label4.Text = "";
}
protected Task<Task> getSerPorts()
{
CmdBoxPort.Text = "";
CmdBoxPort.Update();
if (!String.IsNullOrEmpty(CmdBoxPort.Text))
{
handleComPort();
return Task.FromResult(Task.CompletedTask);
}
else
{
loadCmdBox();
return Task.FromResult(Task.CompletedTask);
}
}
private void ExitButton_Click(object sender, EventArgs e)
{
SerialPortService.CleanUp();
this.Close();
}
private void RefreshButton_Click(object sender, EventArgs e)
{
refresh();
}
protected Task<Task> refresh()
{
label2.Text = "";
label3.Text = "";
label4.Text = "";
CmdBoxPort.Items.Clear();
getSerPorts();
return Task.FromResult(Task.CompletedTask);
}
protected virtual void DetectChange(EventType changedArgs)
{
if (changedArgs == EventType.Insertion)
{
try
{
Task tr = (Task)Invoke(new Action( () => { getSerPorts(); }));
Task rr = (Task)Invoke(new Action(() => { refresh(); }));
}
catch (Exception ex) { MessageBox.Show("Exception at insertion invoke method " + ex, "Exception", MessageBoxButtons.OK); }
}
else if (changedArgs == EventType.Removal)
{
try
{
Task tr = (Task)Invoke(new Action( () => { getSerPorts(); }));
Task rr = (Task)Invoke(new Action(() => { refresh(); }));
}
catch (Exception ex) { MessageBox.Show("Exception at removal invoke method " + ex, "Exception", MessageBoxButtons.OK); }
}
return;
}
}
public static class SerialPortService
{
private static SerialPort _serialPort;
private static string[] _serialPorts;
private static ManagementEventWatcher arrival;
private static ManagementEventWatcher removal;
private static readonly SerialMethods SD = new SerialMethods();
static SerialPortService()
{
_serialPorts = SerialPort.GetPortNames();
MonitorDeviceChanges();
}
public static void CleanUp()
{
arrival.Stop();
removal.Stop();
}
public static event EventHandler<PortsChangedArgs> PortsChanged;
private static void MonitorDeviceChanges()
{
try
{
var deviceArrivalQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
var deviceRemovalQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3");
arrival = new ManagementEventWatcher(deviceArrivalQuery);
removal = new ManagementEventWatcher(deviceRemovalQuery);
arrival.EventArrived += (o, args) => RaisePortsChangedIfNecessary(EventType.Insertion);
removal.EventArrived += (sender, eventArgs) => RaisePortsChangedIfNecessary(EventType.Removal);
// Start listening for events
arrival.Start();
removal.Start();
}
catch (ManagementException err)
{
MessageBox.Show("Management exception = " + err, "Info", MessageBoxButtons.OK);
}
}
private static void RaisePortsChangedIfNecessary(EventType eventType)
{
lock (_serialPorts)
{
var availableSerialPorts = SerialPort.GetPortNames();
if (eventType == EventType.Insertion)
{
var added = availableSerialPorts.Except(_serialPorts).ToArray();
_serialPorts = availableSerialPorts;
PortsChanged.Raise(null, new PortsChangedArgs(eventType, added));
}
else if (eventType == EventType.Removal)
{
var removed = _serialPorts.Except(availableSerialPorts).ToArray();
_serialPorts = availableSerialPorts;
PortsChanged.Raise(null, new PortsChangedArgs(eventType, removed));
}
}
}
public static void Raise<T>(this EventHandler<T> handler, object sender, T args) where T : EventArgs
{
handler?.Invoke(sender, args);
}
}
public enum EventType
{
Insertion,
Removal,
}
public class PortsChangedArgs : EventArgs
{
private readonly EventType _eventType;
private readonly string[] _serialPorts;
public PortsChangedArgs(EventType eventType, string[] serialPorts)
{
_eventType = eventType;
_serialPorts = serialPorts;
}
public string[] SerialPorts => _serialPorts;
public EventType EventType => _eventType;
}
}
Just took a short look at this. It seems like getSerPorts() will always execute loadCmdBox() (CmdBoxPort.Text = ""; ... if (!String.IsNullOrEmpty(CmdBoxPort.Text))) that will attach a new event handler (previous attached event handlers will not be removed by attaching a new one).
You should either remove the existing event handler befor attaching a new one or only attach the event handler once.

C# List.Add System.InvalidOperationException

I am handling an event from a child form in its parent form, and when I try adding items from the list contained within the event args of the handler (ScraperForm_SiteScraped in the code below), I am receiving the exception System.InvalidOperationException in my console.
Interestingly enough, it seems to succeed on the first add, but no subsequent attempts.
public partial class ProxyTesterView : UserControl
{
private BindingList<Proxy> proxies = new BindingList<Proxy>();
private BindingList<ProxyJudge> pudges = new BindingList<ProxyJudge>();
private BindingList<ProxyTest> tests = new BindingList<ProxyTest>();
private PauseOrCancelTokenSource pcts = new PauseOrCancelTokenSource();
private ProxyScraperForm scraperForm = new ProxyScraperForm();
public ProxyTesterView()
{
InitializeComponent();
proxies.ListChanged += Proxies_ListChanged;
scraperForm.SiteScraped += ScraperForm_SiteScraped;
}
private void Proxies_ListChanged(object sender, ListChangedEventArgs e)
{
ProxiesDataGridView.RowCount = proxies.Count;
}
private void AddFromScraperToolStripMenuItem_Click(object sender, EventArgs e)
{
scraperForm.Show();
}
private void ScraperForm_SiteScraped(object sender, SiteScrapedEventArgs e)
{
foreach (var proxy in e.ScrapedProxies)
{
proxies.Add(proxy);
}
}
}
Child Form
public partial class ProxyScraperForm : Form
{
private BindingList<IProxyScraperSite> sites = new BindingList<IProxyScraperSite>();
public int ScrapeInterval { get; set; } = 60000;
public event EventHandler<SiteScrapedEventArgs> SiteScraped;
public ProxyScraperForm()
{
InitializeComponent();
sites.Add(new ProxyScraperSiteUsProxyOrg());
sites.Add(new ProxyScraperSiteFreeProxyListNet());
sites.Add(new ProxyScraperSiteFreeProxyListsNet());
sites.Add(new ProxyScraperSiteHideMyName());
sites.Add(new ProxyScraperSiteHidester());
ScraperDataGridView.DataSource = sites;
}
private void ScrapeButton_Click(object sender, EventArgs e)
{
foreach (var site in sites)
{
Task.Run(async () =>
{
while (true)
{
var driver = SeleniumUtility.CreateDefaultFirefoxDriver();
var newProxies = await site.ScrapeAsync(driver);
driver.Quit();
OnSiteScraped(newProxies);
await Task.Delay(5000);
site.Status = $"Waiting {ScrapeInterval / 1000} seconds...";
await Task.Delay(ScrapeInterval);
}
});
}
}
private void OnSiteScraped(List<Proxy> scrapedProxies)
{
if (SiteScraped != null)
{
SiteScraped(this, new SiteScrapedEventArgs(scrapedProxies));
}
}
}
From our comments, turns out that this was a threading issue. As a good practice, always use a try/catch block when there's a chance that an exception can occur in a block of code. :)
Also, if you're using Visual Studio, you can make VS break on more exceptions by pressing CTRL+ALT+E and selecting the checkboxes. You can read more about exception breaking here.

How do i activate this code with a Button?

As title says. I want to activate this code with a button in FormsApp, but i really do not how to do it.
public static async Task<List<string>> GetProxiesFromSslProxies()
{
try
{
string rssContent = await new WebClient().DownloadStringTaskAsync("http://sslproxies24.blogspot.de/feeds/posts/default");
XDocument feed = XDocument.Parse(rssContent);
SyndicationFeed sf = SyndicationFeed.Load(feed.CreateReader());
List<string> allProxies = new List<string>();
foreach (SyndicationItem si in sf.Items)
{
var cont = (TextSyndicationContent) si.Content;
var matches = Regex.Matches(cont.Text, #"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]{2,6}\b");
allProxies.AddRange(from Match match in matches select match.Value);
}
return allProxies.Distinct().ToList();
}
catch (Exception)
{
}
return null;
}
You have to add a button handler to your button. Then you invoke your method in the handler. You can attach the handler in the WinForms designer - just double click the button. Or you can add it in the constructor of your form:
public Form1()
{
InitializeComponent();
this.button1.Click += new System.EventHandler(this.button1_Click);
}
And the handler:
private async void button1_Click(object sender, EventArgs e)
{
var results = await GetProxiesFromSslProxies();
}
private async void Button_Click( ... )
{
List<string> proxies = await GetProxiesFromSslProxies();
//do something with 'proxies'.
}

Async wait until form is loaded to continue

I am trying to get my form to wait until a particular part of my _Load method is finished before continuing. I have a few methods that are async, but I cannot figure out why I am not able to get the code to wait until fakeClickCheckUpdate is finished before continuing. Here are the main methods involved:
public myForm(string args)
{
InitializeComponent();
Load += myForm_Load;
}
private void myForm_Load(object s, EventArgs e)
{
this.fakeClickCheckUpdate();
loadFinished = true;
if (this.needsUpdate == true)
{
Console.WriteLine("Needs update...");
}
else
{
Console.WriteLine("update is false");
}
}
public void fakeClickCheckUpdate()
{
this.checkUpdateButton.PerformClick();
}
private async void checkUpdateButton_Click(object sender, EventArgs e)
{
await startDownload(versionLink, versionSaveTo);
await checkVersion();
Console.WriteLine(needsUpdate);
}
private async Task checkVersion()
{
string currVersion;
string newVersion;
using (StreamReader sr = new StreamReader(currVersionTxt))
{
currVersion = sr.ReadToEnd();
}
using (StreamReader nr = new StreamReader(versionSaveTo))
{
newVersion = nr.ReadToEnd();
}
if (!newVersion.Equals(currVersion, StringComparison.InvariantCultureIgnoreCase))
{
this.BeginInvoke((MethodInvoker)delegate
{
progressLabel.Text = "New version available! Please select 'Force Download'";
});
this.needsUpdate = true;
}
else
{
this.BeginInvoke((MethodInvoker)delegate
{
progressLabel.Text = "Your version is up-to-date. No need to update.";
});
this.needsUpdate = false;
}
}
Basically, I want it to check the current version with checkVersion and finish that before it tries to continue past loadFinished = true inside of myForm_Load. I have checkVersion set as an async Task so that the button click can use await on it. Is there any way to get the functionality I need with this code?
First, move your code out of your perform click action.
private async void checkUpdateButton_Click(object sender, EventArgs e)
{
await CheckForUpdate();
}
private async Task CheckForUpdate()
{
await startDownload(versionLink, versionSaveTo);
await checkVersion();
Console.WriteLine(needsUpdate);
}
You can then call that same function in your OnLoad.
private async void myForm_Load(object s, EventArgs e)
{
await CheckForUpdate();
loadFinished = true;
if (this.needsUpdate == true)
{
Console.WriteLine("Needs update...");
}
else
{
Console.WriteLine("update is false");
}
}

Categories