How to Control the time between each Post Using Facebook Sdk C# - c#

I am using Facebook Sdk C# To develop a desktop program for publication posts in Facebook groups. The software will publish very quickly I need a way to control the speed of publication and capping for publication not less than 10 seconds between each publication and the other. How to do like this methods ?
My class
public static string UploadPost(string groupid, string intTitle, string inMessage, string inLinkCaption, string inLinkUrl, string inLinkDescription, string inLinkUrlPicture)
{
object obj;
Facebook.JsonObject jsonObj;
FacebookClient client;
string access_token = AppSettings.Default.AccessToken.ToString();
client = new FacebookClient(access_token);
var args = new Dictionary<string, object>();
args["message"] = inMessage;
args["caption"] = inLinkCaption;
args["description"] = inLinkDescription;
args["name"] = intTitle;
args["picture"] = inLinkUrlPicture;
args["link"] = inLinkUrl;
if ((obj = client.Post("/" + groupid + "/feed", args)) != null)
{
if ((jsonObj = obj as Facebook.JsonObject) != null)
{
if (jsonObj.Count > 0)
return jsonObj[0].ToString();
}
}
return string.Empty;
}
internal static bool UploadPost(string p1, string p2)
{
throw new NotImplementedException();
}
}
}
My submit button
private void btnPost_Click(object sender, EventArgs e)
{
for (int i = 0; i < lstgroupsbox.Items.Count; i++)
{
if (Class1.UploadPost(lstgroupsbox.Items[i].ToString(), "amine", txtStatus.Text, "googl", txtLink.Text, "seach", txtImagePath.Text) != string.Empty)
label23.Text=""+lstgroups.Items[i].Text;
}
//foreach (var item in lstgroupsbox.Items)
//{
// if (Class1.UploadPost(item.ToString(), "amine", txtStatus.Text, "googl", 2, "seach", txtImagePath.Text) != string.Empty)
// label23.Text=""+lstgroups.Items[i].Text;
//}
}

I suggest you look into the Timer class. This one way you could do this:
Create a ConcurrentQueue (not a normal Queue because it's not thread-safe, look into thread safety) in your main class. This is your upload "job list". Add also a Timer and create an event handler method for its Elapsed event (refer to the first link in this answer for instructions). The event handler method is what will execute your jobs.
Then create a new class that holds a post's info and the details needed to upload it. This is your upload job class.
In your for loop inside your submit button's event handler, instead of uploading the images, you create instances of that job class and enqueue them into your job list (the ConcurrentQueue). After they're all added, you start your main class' Timer. The Elapsed event handler method mentioned earlier will take the next item from the queue (or stop if it's empty?) and upload it to Facebook.
EDIT:
So, in your form class, add a using statement first:
using System.Collections.Concurrent;
Then add these near the top of the class:
private System.Timers.Timer _jobTimer = new Timer(10000);
private ConcurrentQueue<UploadJob> _jobQueue = new ConcurrentQueue<UploadJob>();
These go to your form's constructor (after the InitializeComponent() method call):
_jobTimer.SynchronizingObject = this;
// ^ The Elapsed event will be run on the same thread as this.
// This way we won't get exceptions for trying to access the form's labels
// from another thread (the Timer is run on its own thread).
_jobTimer.Elapsed += OnJobTimedEvent;
Then you add the OnJobTimedEvent method somewhere in your form class:
private void OnJobTimedEvent(object sender, ElapsedEventArgs e)
{
UploadJob job;
if (_jobQueue.TryDequeue(out job)) // Returns false if it fails to return the next object from the queue
{
if (Class1.UploadPost(job.Group,
job.Name,
job.Message,
job.Caption,
job.Link,
job.Description,
job.Picture) != string.Empty)
{
// Post was uploaded successfully
}
}
else
{
// I believe we can assume that the job queue is empty.
// I'm not sure about the conditions under which TryDequeue will fail
// but if "no more elements" isn't the only one, we could add
// (_jobQueue.Count == 0)
// to the if statement above
_jobTimer.Stop();
// All uploads complete
}
}
As you can see, it uses UploadJob. That class can be separated into a separate file altogether:
public class UploadJob
{
public string Group { get; protected set; }
public string Name { get; protected set; }
public string Message { get; protected set; }
public string Caption { get; protected set; }
public string Link { get; protected set; }
public string Description { get; protected set; }
public string Picture { get; protected set; }
public UploadJob(string group,
string name,
string message,
string caption,
string link,
string description,
string picture)
{
Group = group;
Name = name;
Message = message;
Caption = caption;
Link = link;
Description = description;
Picture = picture;
}
}
and finally we get to your button click event handler:
private void btnPost_Click(object sender, EventArgs e)
{
for (int i = 0; i < lstgroupsbox.Items.Count; i++)
{
_jobQueue.Enqueue(lstgroupsbox.Items[i].ToString(),
"amine",
txtStatus.Text,
"googl",
txtLink.Text,
"seach",
txtImagePath.Text);
}
_jobTimer.Start();
}
Personally I would probably separate all this into an UploadManager class or something and let that class worry about the timer and everything, but this should work just fine.

Related

How to instantiate a new Windows Form with Quartz.NET without problems?

I'm using the Quartz.NET library to create a job in my C# application.
I have some registers in my database, so I have a table wich contains a column called "start_date". The job runs every 50 seconds, so I compare the dates from the column "start_date" with the date of my computer, and if the dates are equal, I want to instantiate a new Windows Form with a message and a button.
At the moment, the new Windows Form is opening at the right moment, but the message is not showed and the window stops to respond.
Basically, in my code I have something like this:
FormMessage.cs
public partial class FormMessage : Form
{
public FormMessage()
{
InitializeComponent();
}
public FormMessage(double minutes)
{
InitializeComponent();
string message = string.Format("You have {0} minutes!", minutes);
lblMessage.Text = message ;
}
private void btnOK_Click(object sender, EventArgs e)
{
this.Close();
}
}
JobMessage.cs
public class JobMessage: IJob
{
List<Information> informations;
public void Execute(IJobExecutionContext context)
{
//Class with methods to get registers from database.
InformationAPI infoAPI = new InformationAPI();
informations = infoAPI.GetInformations();
foreach (Information info in informations)
{
DateTime computerDateTime = DateTime.Now;
DateTime infoDateTime = info.StartDate;
double difference;
if (DateTime.Compare(computerDateTime, infoDateTime) < 0)
{
difference = Math.Round(infoDateTime.Subtract(computerDateTime).TotalMinutes);
if (difference == 5)
{
FormMessage formMessage = new FormMessage(difference);
formMessage.Show();
}
}
}
}
}
Someone have some idea of the reason why the FormMessage window stops to respond?
Thank you for your attention!
You can try Quartz Listeners to let them open the form to show the data and keep the execution out of the job scope:
Action<IJobExecutionContext, JobExecutionException> listenerAction = (c, e) => {
var dataMap = context.GetJobDetail().GetJobDataMap();
var difference = dataMap.GetIntValue("difference");
FormMessage formMessage = new FormMessage(difference);
formMessage.Show();
}
var listener = new SyncJobListener(listenerAction);
And add the listener in to the scheduler:
scheduler.ListenerManager.AddJobListener(listener,
GroupMatcher<JobKey>.GroupEquals("GroupName"));
Using this SyncJobListener:
public class SyncJobListener : IJobListener
{
private readonly Action<IJobExecutionContext, JobExecutionException> _syncExecuted;
public string Name { get; private set; }
public SyncJobListener(
Action<IJobExecutionContext, JobExecutionException> syncExecuted
)
{
Name = Guid.NewGuid().ToString();
_syncExecuted = syncExecuted;
}
public void JobToBeExecuted(IJobExecutionContext context)
{
}
public void JobExecutionVetoed(IJobExecutionContext context)
{
}
public void JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException)
{
_syncExecuted(context, jobException);
}
}
I have not tested this so if the dataMap does not have any data, you are going to need to allow the persistance:
[PersistJobDataAfterExecution]
[DisallowConcurrentExecution]
public class JobMessage: IJob {}

How can I order the processing of events in WPF/c#?

I am working on a cardgame conform the MVVM pattern. My model contains the players, hands and cards as well as the game with its rules.
There are 2 classes not playing nice here: the "card" class that has a "submitted" event: when a player clicks on an image of the card, among other things the submitted event fires. This triggers the UI to move the card from a hand to the center of the window.
Next I have a class "trick", that all players add a card to. When the trick is full, it fires the TrickFull event: this triggers the UI to show the cards in the trick and then clear the table.
During gameplay the TrickFull event fires nanoseconds after the last card was submitted. This means the table is cleared before the 4th card can be shown. I would like to be able to force the UI to process the cardsubmitted event before the Trickfull event.
I have tried to accomplish this by Thread.Sleep (which does not work), I have also tried to move the TrickFull event to the gameclass (meaning it gets triggered much later). This works, but it does seem very out of place. I have looked into locking the events (but that does not seem to be the way to go), directly taking to control of the Dispatcher, changing the priority, or maybe calling the events asynchonously and blocking the stuff somehow in the EndInvoke.
I would like to know what the best solution for this would be. My research suggests that maybe Events would not be the best pattern for this behaviour, but I am stumped. Can you bright people please advise me on how to fix this (probably architectural) flaw?
Code below, beware: Dutch classnames and stuff in there
Card (=Kaart)
public class Kaart : IComparable<Kaart>
{
public readonly Kleur Kleur;
public readonly Waarde Waarde;
public Kaart(Kleur kleur, Waarde waarde)
{
Kleur = kleur;
Waarde = waarde;
}
public event KaartGespeeld Opgegooid;
public delegate void KaartGespeeld(Kaart kaart);
public void Opgooien()
{
Opgegooid?.Invoke(this);
}
public int CompareTo(Kaart other)
{
var comparer = new KlaverjasComparer(null, null);
return comparer.Compare(this, other);
}
public Speler Speler { get; set; }
}
Trick (=Slag)
public class Slag
{
private readonly List<Kaart> _kaarten;
[Browsable(false)]
public IReadOnlyList<Kaart> Kaarten => _kaarten;
public Slag(Kleur troef)
{
_kaarten = new List<Kaart>(4);
Troef = troef;
}
public Speler Winnaar { get; private set; }
public int Punten => PuntenTeller.Punten(this);
public int Roem => PuntenTeller.Roem(this);
[Browsable(false)]
public Kleur Troef { get; }
public Kleur GevraagdeKleur { get; set; }
[Browsable(false)]
public bool Vol =>_kaarten.Count == 4;
public void Add(Kaart kaart)
{
if (!Vol)
{
if (_kaarten.Count == 0)
{
GevraagdeKleur = kaart.Kleur;
}
_kaarten.Add(kaart);
}
else
{
throw new Exception("Te veel kaarten in een slag");
}
if (!Vol) return;
Winnaar = bepaalHoogsteKaart(this).Speler;
VolleSlag?.Invoke(this);
}
public event SlagIsVol VolleSlag;
public delegate void SlagIsVol(Slag slag);
}
ViewModel:
public TafelViewModel(Boompje boompje)
{
Speler1 = boompje.Deelnemers[0];
Speler2 = boompje.Deelnemers[1];
Speler3 = boompje.Deelnemers[2];
Speler4 = boompje.Deelnemers[3];
Troef = boompje.Potje.Troef;
//boompje.SlagIsVol += Boompje_SlagIsVol;
// ToDo: als ik naar dit event kijk gaat het mis
boompje.Potje.Slag.VolleSlag += Boompje_SlagIsVol;
boompje.Potje.TroefGedraaid += delegate { Troef = boompje.Potje.Troef; };
foreach (Speler _deelnemer in boompje.Deelnemers)
{
foreach (Kaart _kaart in _deelnemer.Hand)
{
_kaart.Opgegooid += moveKaart;
}
_deelnemer.DoeIkHet += DeelnemerOnDoeIkHet;
}
_spelerKaart = new Dictionary<Speler, string>
{
{Speler1, "Kaart1"},
{Speler2, "Kaart2"},
{Speler3, "Kaart3"},
{Speler4, "Kaart4"}
};
_spelerRichting = Dictionary.SpelersRichting(boompje.Deelnemers);
WinnaarVisible = Visibility.Hidden;
}
private void Boompje_SlagIsVol(Slag slag)
{
WinnaarVisible = Visibility.Visible;
Richting = _spelerRichting[slag.Winnaar];
Application.DoEvents();
Thread.Sleep(2000);
Kaart1 = null;
Kaart2 = null;
Kaart3 = null;
Kaart4 = null;
WinnaarVisible = Visibility.Hidden;
}
private void moveKaart(Kaart kaart)
{
PropertyInfo prop = GetType().GetProperty(_spelerKaart[kaart.Speler]);
prop?.SetValue(this, kaart);
}
public void OpKaartGeklikt(Kaart kaart)
{
if (kaart.Speler != Speler3)
{
return;
}
Speler3.SpeelKaart(kaart);
}
}
}
Set ManualResetEvent in your ViewModel
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
Pass this object into Kaart of yours
ManualResetEvent _manualResetEvent;
public Kaart(Kleur kleur, Waarde waarde, ManualResetEvent manualResetEvent)
{
Kleur = kleur;
Waarde = waarde;
_manualResetEvent = manualResetEvent;
}
This is the method that's being invoked when card is added I assume
public void Opgooien()
{
Opgegooid?.Invoke(this);
_manualResetEvent.Set();
}
And the main part (you also need to pass ManualResetEvent to the Slag object.
public void Add(Kaart kaart)
{
if (!Vol)
{
if (_kaarten.Count == 0)
{
GevraagdeKleur = kaart.Kleur;
}
_kaarten.Add(kaart);
}
else
{
throw new Exception("Te veel kaarten in een slag");
}
if (!Vol) return;
Winnaar = bepaalHoogsteKaart(this).Speler;
var result = _manualResetEvent.WaitOne(TimeSpan.FromSeconds(5));
if(!result)
{
/* Did not receive signal in 5 seconds */
}
VolleSlag?.Invoke(this);
_manualResetEvent.Reset();
}
Just the basic concept, it might not work right away due to your code language and lack of some part of it in the example, but you should catch the idea

How can I add to a listbox from another class?

I've seen this posted a few times but I cannot seem to get it to apply for me.
I want to add items to a listbox which is in my home class from my ServerController class.
Not entirely sure on how to go about this so any help would be grateful.
Home Class:
public partial class frmHome : Form
{
serviceController sc = new serviceController();
public ListBox lb = new ListBox();
public frmHome()
{
lb = new ListBox();
InitializeComponent();
serviceController sc = new serviceController();
}
//ListBox Add
public void addItem(string item)
{
lb_msg.Items.Add(item);
lb_msg.Items.Add(item);
lb_msg.Items.Add("");
}
}
Service Class:
public class serviceController
{
ServiceController[] scServices;
//Start the service
public void startServices()
{
scServices = ServiceController.GetServices();
try
{
foreach (ServiceController scTemp in scServices)
{
if (scTemp.ServiceName == "MSSQL$SQLSERVER" || scTemp.ServiceName == "SQLBrowser")
{
if (scTemp.Status == ServiceControllerStatus.Stopped)
{
//Check to see if service is disabled
home.addItem("Attempting to start " + scTemp.ServiceName);
scTemp.Start();
scTemp.WaitForStatus(ServiceControllerStatus.Running);
}
if (scTemp.Status == ServiceControllerStatus.Running)
{
home.addItem(scTemp.ServiceName + " is running");
}
}
else if (scTemp.Status == ServiceControllerStatus.Running)
{
home.addItem(scTemp.ServiceName + " is already running");
}
}
serverStatus();
}
catch (Exception ex)
{
throw ex;
}
}
On the Service Class I want to use home.addItem
Am I write in thinking I need to make a public listbox in my home class and link it with the one in my design?
What I want to achieve is this:
I want it to check x amount of services to see the status of it. If it is stopped, then check if it is disabled and report back - if it is disabled attempt to set as automatic, else attempt to start it. I want to write a log as it does this.
Hope this gives a bit more clarification.
Thanks!!!
You could pass it through the constructor
public class serviceController
{
private ListBox home;
public serviceController(ListBox lb)
{
home = lb;
}
public void foo()
{
home.Items.Add("")
}
}
Now, when you create a new object of serviceController, you need to pass a listbox.
serviceController sv = new serviceController(lb_msg);
Then, when you are in the serviceController, you can use the variable lb like you could in the main class
another way of accessing other form controls is
frmHome form = new frmHome();
ListBox lb = (ListBox)form.Controls["nameOfControl"];
lb.Items.Add("");
also: serviceController should start with an uppercase, ServiceController
I have written a sample code to demonstrate what I suggested. You have to match it with the actual types (classes e.g.) you're using. Added code comments, so I'm not going to write much here again. If you want to play with this code, here's a fiddle: https://dotnetfiddle.net/t0MyNk
public class Program // Consider this your home form
{
public void Main()
{
var serviceController = new ServiceController();
serviceController.ServiceStateChange += ServiceController_ServiceStateChanged;
serviceController.StartServices();
}
private void ServiceController_ServiceStateChanged(object sender, ServiceControllerEventArgs e)
{
// Add to listbox or do whatever you want. I am just printing.
Console.WriteLine(e.Message);
}
}
public class ServiceController
{
public event EventHandler<ServiceControllerEventArgs> ServiceStateChange;
public void StartServices()
{
Service[] services = new Service[] // Sample services data
{
new Service { Name = "MSMQ", Status = "Stopped" },
new Service { Name = "W3SVC", Status = "Running" }
};
string message = null;
foreach(Service s in services)
{
if(s.Status == "Stopped")
{
s.Start();
// Assuming it starts almost immediately. If not, you could follow same pattern for
// Service class where an event will be raised once service is "actually" started.
if(s.Status == "Running") {
message = string.Format("Service {0} is {1}", s.Name, s.Status);
}
}
else if(s.Status == "Running") {
message = string.Format("Service {0} is already {1}", s.Name, s.Status);
}
// Now tell subscriber (home form) about this.
OnServiceStateChange(message);
}
}
private void OnServiceStateChange(string message)
{
var serviceStateChangeHandler = ServiceStateChange;
if(serviceStateChangeHandler != null)
{
serviceStateChangeHandler(this, new ServiceControllerEventArgs { Message = message });
}
}
}
// You could have custome delegate type for event to return string message.
// But IMO this is much cleaner, and as per MSFT guidelines.
public class ServiceControllerEventArgs : EventArgs
{
// You can also return Service instance
// Just including Message for now
public string Message { get; set; }
}
// for demo purpose, represents individual service.
public class Service
{
public string Name { get; set; }
public string Status { get; set; }
public void Start() {
Status = "Running";
}
}
Output:
Service MSMQ is Running
Service W3SVC is already Running
I would strongly recommend you adopt binding instead of manipulating the controls on your forms directly, with the goal of keeping data and UI separate. You could for instance have a list (it would have to be a BindingList<> if memory serves) of strings in your class, and the list control would bind to it; that way the contents of the list are reflected in the UI and you can freely update the list from somewhere else as just data, without having to think about the intricacies of how the data is presented.
In the end you could come up with something similar to MVVM (model-view-viewmodel) or MVC, which in my opinion are superior solutions to manipulating controls manually.

Updating listviews every second from different threads

I am updating a "timer" field in my listView from different threads. It works fine, the problem is just that it flickers. This is the code each thread is calling when it needs to be updated (almost every second).
private void AddToListView(string user, string status, string proxy, int number)
{
Invoke(new MethodInvoker(
delegate
{
listView1.BeginUpdate();
this.listView1.Items[number].SubItems[1].Text = status;
listView1.EndUpdate();
}
));
}
Having Googled a bit im not even sure i can make this flicker go away? :/
I would not use Invoke here. In fact, in most cases it is usually not a great option despite what you may read on the internet. Instead, package up the data being generated by the thread into a POCO and put it into a queue. Have a System.Windows.Forms.Timer tick every second with the event handler pulling items out of the queue to update the ListView in batches. Also, try setting DoubleBuffered to true. These suggestions should help some.
public class YourForm : Form
{
private ConcurrentQueue<UpdateInfo> queue = new ConcurrentQueue<UpdateInfo>();
private void YourTimer_Tick(object sender, EventArgs args)
{
UpdateInfo value;
listView1.BeginUpdate();
while (queue.TryDequeue(out value)
{
this.listView1.Items[value.Number].SubItems[1].Text = value.Status;
}
listView1.EndUpdate();
}
private void SomeThread()
{
while (true)
{
UpdateInfo value = GetUpdateInfo();
queue.Enqueue(value);
}
}
private class UpdateInfo
{
public string User { get; set; }
public string Status { get; set; }
public string Proxy { get; set; }
public int Number { get; set; }
}
}

Dictionary containing objects with Timers. Need to find out which object's timer is calling the elapsed event

i have this poll class
class Poll
{
public string question { get; set; }
public Timer pollTimer { get; set; }
public List<string> userVoted { get; set; }
public Dictionary<string, int> choices { get; set; }
public bool PollRunning { get; set; }
public Poll(string question,Dictionary<string,int> choices)
{
this.question = question;
this.choices = choices;
this.pollTimer = new Timer(15000);
this.PollRunning = true;
this.userVoted = new List<string>();
}
public string pollResults()
{
string temp = "";
foreach (KeyValuePair<string, int> keyValuePair in choices)
{
temp = temp + keyValuePair.Key + " " + keyValuePair.Value + ", ";
}
return string.Format("Poll Results: {0}", temp);
}
}
and I have this code in a StartPool method
static Dictionary<Channel, Poll> polls = new Dictionary<Channel, Poll>();
public void startPool(Channel channel)
{
polls.Add(channel, new Poll(question, tempdict));
polls[channel].pollTimer.Elapsed += new ElapsedEventHandler(pollTimer_Elapsed);
polls[channel].pollTimer.Start();
}
When this method gets called
static void pollTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//do stuff to the poll that called this.
}
I need know what poll object's timer is calling this method
so I can do polls[channel].pollTimer.Stop(); and do polls[channel].pollResults();
As it is I have no idea which poll stop and post results for when this runs
i'm willing to post entire solution if that will help you help me.
The problem with the way you've designed the Poll class is that the Poll class doesn't completely do its job. You require other classes to know how to start and stop polling, meaning half of the polling implementation is inside the Poll class and half of the implementation is outside the Poll class. If you're going to create a Poll class, hide ALL the implementation details from everyone else.
Here is what I mean. I would create an event in Poll like this:
public event EventHandler<ElapsedEventArgs> Elapsed;
In Poll's constructor, add this line:
this.pollTimer.Elapsed += pollTimer_elapsed;
and the pollTimer_elapsed looks like this:
private void pollTimer_elapsed(object sender, ElapsedEventArgs e)
{
var han = this.Elapsed;
if (han != null)
han(this, e); // Fire the Elapsed event, passing 'this' Poll as the sender
}
Add a new public method in Poll to start the timer:
public void Start()
{
this.pollTimer.Start();
}
So now your startPool method looks like this:
public void startPool(Channel channel)
{
polls.Add(channel, new Poll(question, tempdict));
polls[channel].Elapsed += poll_Elapsed;
polls[channel].Start();
}
static void poll_Elapsed(object sender, ElapsedEventArgs e)
{
//sender is now a Poll object
var poll = sender as Poll;
// Now you can do poll.pollTimer.Stop()
// Or better yet, add a Stop method to the Poll class and call poll.Stop()
}
IMHO this approach is slightly better because the Poll object is hiding more of its implementation from external objects. From startPool's point of view, the Poll class is simpler to use, and you also don't require anything outside of your Poll class to know about Timers.
you can add a property :
public bool pollTimerElapsed { get; set; }
and subscribe a handler in the contsructeur of Poll of Elapsed event of pollTimer where you set to true the property pollTimerElapsed
then you can filter elapsed Polls by this property

Categories

Resources