How to get "previous" and "next" functionality? - c#

I have a program that people can leave comments on a video. The comments come is as in queue status. The admin can go into the admin section and mark the comments as either approved or removed. They want to be able to automatically go to the next item marked in queue when they press either the previous or next buttons, as well as if they approve or remove a comment. I do not know jQuery or JavaScript well enough to know if it is possible to do it using those, or how to do it through the code behind (this is in C# .NET). Any help would be appreciated:
Status and value:
In queue = 0
Approved = 1
Removed = 2
Here is the code-behind. The status changes work, the only thing I cannot do is have it go to the next record marked in queue. The first two events are blank because I do not know how to fill them, but simply put, all the need to do too is go to the next record marked in queue.
If you need any more code, please let me know...
protected void previous_clicked(object sender, EventArgs e)
{
}
protected void next_clicked(object sender, EventArgs e)
{
}
protected void approve_clicked(object sender, EventArgs e)
{
currentMessage = new videomessage(Request["id"].ToString());
status.SelectedValue = "1";
currentMessage.status = "1";
currentMessage.Save();
}
protected void remove_clicked(object sender, EventArgs e)
{
currentMessage = new videomessage(Request["id"].ToString());
status.SelectedValue = "2";
currentMessage.status = "2";
currentMessage.Save();
}

Sounds more like an architectural challenge to me.
I recommend using a Queue. This is a collection type following a first-in, first-out (FIFO) approach. You put objects into the queue and get them back out in the same order. An object that was received out of this queue is automatically is removed from the queue, so you can be sure that you do not handle the same element twice.
Your described workflow then would work as these simple steps:
Whenever a message arrives, you put the object into your queue.
When the admin clicks on the next button, you request the first object out of the queue.
Your admin does his administrative tasks and approves the message.
Clicking on Next start with above item 1 again.
[EDIT]
Oops, I realized that my Queue approach would not allow for navigating back to previous items.
In this case I suggest using a simple List collection. This list can be accessed via the 0-based position in the list. This makes it easy to implement a forward/ backward navigation.
For my sample code, please bear in mind that there is a lot that I cannot know about your environment, so my code make a lot assumptions here.
You need to somwhere store a collection that contains your messages to be approved:
private IList<videomessage> _messagesToApprove = new List<videomessage>();
You will also need some variable that keeps track of the current position in your collection:
// Store the index of the current message
// Initial value depends on your environment. :-)
private int _currentIndex = 0;
To begin with, you will need a starting point where new messages are added to that collection, like subscribing to some event or so. Whenever a message arrives, add it to the collection by calling a method like:
// I made this method up because I do not know where your messages really come from.
// => ADJUST TO YOUR NEEDS.
private void onNewMessageArriving(string messageId)
{
videomessage arrivingMessage = new videomessage(messageId);
_messagesToApprove.Add(arrivingMessage);
}
The you can easily implement the navigation by incrementing/ decrementing the position index:
private void previous_Click(object sender, EventArgs e)
{
// Check that we do not go back further than the beginning of the list
if ((_currentIndex - 1) >= 0)
{
_currentIndex--;
this.currentMessage = this._messagesToApprove[_currentIndex];
}
else
{
// Do nothing if the position would be invalid
return;
}
}
private void next_Click(object sender, EventArgs e)
{
// Check if we have new messages to approve in our list.
if ((_currentIndex + 1) < _messagesToApprove.Count)
{
_currentIndex++;
currentMessage = _messagesToApprove[_currentIndex];
}
else
{
// Do nothing if the position would be invalid
return;
}
}
private void approve_Click(object sender, EventArgs e)
{
// Sorry, I don't know where exactly this comes from, needs to be adjusted to your environment
status.SelectedValue = "1";
this.currentMessage.status = "1";
this.currentMessage.Save();
// If you want to remove items that have been checked by the admin, delete it from the approval list.
// Otherwise remove this line :-)
this._messagesToApprove.RemoveAt(_currentIndex);
}
private void remove_Click(object sender, EventArgs e)
{
// Sorry, I don't know where exactly this comes from, needs to be adjusted to your environment
status.SelectedValue = "2";
this.currentMessage.status = "2";
this.currentMessage.Save();
// If you want to remove items that have been checked by the admin, delete it from the approval list.
// Otherwise remove this line :-)
this._messagesToApprove.RemoveAt(_currentIndex);
}

Save the id of current comment in session or viewstate get it back on next or previous button click and display the accordingly:
Session["id"] = 2;
int id = (int) Session["id"];

Related

How to change the web browser control properties?

I am creating a web browser using c# winform. I am using webbrowser control for this. I am using this code. This is running good so far
// Declared Variables
private string[] SiteMemoryArray = new string[100];
private int count = 0;
// Page Load
private void Form1_Load(object sender, EventArgs e)
{
webBrowser.Navigate("http://www.google.com/"); // Goes To A Preset Site At Run Time
SiteMemoryArray[count] = urlTextBox.Text; // Saves URL To Memory
}
// Code For The ToolStrip
// URL TextBox
private void urlTextBox_Click(object sender, EventArgs e)
{
urlTextBox.SelectAll(); // Selects All The Text In The urlTexBox
}
// GO Button
private void goButton_Click(object sender, EventArgs e)
{
webBrowser.Navigate(urlTextBox.Text); // Navigates To The Site Typed In The urlTextBox
}
// Back Button
private void backButton_Click(object sender, EventArgs e)
{
if (count > 0) // Checks To Make Sure The Count Variable Is More Then 0
{
count = count - 1; // Subtracts 1 From Count Variable
urlTextBox.Text = SiteMemoryArray[count]; // Replace The Text In The urlTextBox With The Last URl
webBrowser.Navigate(urlTextBox.Text); // Navigates To The Site Typed In The urlTextBox
forwardButton.Enabled = true; // Enables The forwarButton
}
}
// Forward Button
private void forwardButton_Click(object sender, EventArgs e)
{
if (count < 100) // Checks To Make Sure The Count Variable Is Less Then 100
{
count = count + 1; // Adds 1 To Count Variable
urlTextBox.Text = SiteMemoryArray[count]; // Replace The Text In The urlTextBox With The Next URl
webBrowser.Navigate(urlTextBox.Text); // Navigates To The Site Typed In The urlTextBox
backButton.Enabled = true; // Enables The backButton
count = count + 1; // Adds 1 To Count Variable
if (SiteMemoryArray[count] == null) // Checks To See If The Next Variable In The SiteMemoryArray Is Null
{
forwardButton.Enabled = false; // Disables The forwarButton
}
count = count - 1; // Subtracts 1 From Count Variable
}
}
But after create this small application my friend who is php developer ask me to check browser name . For this he create a php script n give me url then i run this url on my this browser its show me the browser name Internet Explorer
Now I want my browser name whatever I give name Please tell me is it possible with this control. Is there any property by using i can change it ?
The web browser control is IE. If you want to create your own browser, it is a lot more work than this. You need to write code that is able to do following and more:
Understand and handle HTTP protocol.
Understand, parse and render HTML. Most browsers ignore certain HTML errors and still render pages accurately. Not sure if you want that kind of features.
Your application should be able apply CSS settings on the pages.
Your application should be able to apply JS, flash, video, audio and other items that may well be embedded on a page.
You would also need to provide features that are available standard browsers.
The question is: What is the purpose of this application? Are you trying to write your own browser?

Weather fetching is not working more than once

I have a problem with the Wunderground forecast that I am using to retrieve data in c# program.
When I click to retrieve data once everything is working correctly but when I hit the button once more I am getting this error:
Here is my code:
private void bweather_DoWork(object sender, DoWorkEventArgs e)
{
string lat = Math.Round(deciLat).ToString();
string lng = Math.Round(deciLon).ToString();
string latlong = String.Format("{0},{1}", lat.Replace(',', '.'), lng.Replace(',', '.'));
//Initialize Current as a new Day
dow.Current = new WeatherLib.WDay();
//Using Wunderground as the provider we populate the property with current data for the latlong entered into the textbox
try
{
dow = WeatherLib.WProvider.Wunderground(latlong);
writeToLogFile("Retrieve weather info successfully on: " + latlong);
}
catch (Exception ex)
{
writeToLogFile(ex.Message);
}
}
Here is the refresh button:
private void weather_refresh_Click(object sender, EventArgs e)
{
writeToLogFile("Weather button pressed");
weather_descripton.Clear();
weather_speed_textbox.Clear();
weather_tem_textbox.Clear();
weather_rain_text.Clear();
weather_wind_dir_textbox.Clear();
weather_descripton.AppendText("Searching.......");
if (!bweather.IsBusy)
{
bweather.CancelAsync();
}
bweather.RunWorkerAsync();
}
And here are the event handlers:
// Weather handlers
bweather.WorkerSupportsCancellation = true;
bweather.DoWork += bweather_DoWork;
bweather.RunWorkerCompleted += bweather_RunWorkerCompleted;
Any idea why is this not working as it should?
Thank you
Well the error message suggests that you're trying to use the same background worker more than once.
You're asking it to cancel if it's still busy, but that doesn't mean it'll cancel immediately. As far as I can tell, the BackgroundWorker code isn't even checking whether it's been cancelled, which means cancelling it won't really achieve anything useful.
I would suggest that if it's busy, you should instead just ignore the request. In fact, it might be better to disable the button completely when you start the operation, and only re-enable it when the operation completes.

How to stop method from calling themselves recursively?

I have two tables, employees and project, in listbox2, I show all the employees and in listbox1 all the projects, now obviously one employee can be involved in many projects and one project could have many employee. So I have this EmployeeProject that maps the many to many relation that exists. What I want is, if user click a project name in first listbox, then all employees in that project should be selected in listbox2. Also, when a user clicks a item in listbox2, (an employee) all project of which that employee is a part should be selected in listbox1
But If I use ListBox.SelectedIndexChanged event for this process, and select even a single value in listbox2 then it would trigger the SelectedIndexChagned for listbox2, and that would start working by selecting all items in listbox1 that current employee is a part of, but again, as soon as even one item in listbox1 is selected, it would fire up its SelectedIndexChanged event, and it would go on forever like this. So what's the solution of this? So far, I've done this..
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
// Load the list of employees
cmd.CommandText =
"SELECT EmpName FROM Employee WHERE EmpID IN(SELECT EmpID FROM EmployeeProject WHERE ProjectID =(SELECT ProjectID FROM Project WHERE ProjectName = '" +
listBox1.SelectedItem.ToString() + "')) ORDER BY EmpId";
var rdr = cmd.ExecuteReader();
listBox2.Items.Clear();
// right now, I am doing this to escape this recursive loop, but thats not what I want
while (rdr.Read())
{
listBox2.Items.Add(rdr.GetString(0));
}
rdr.Close();
this.AutoScroll = true;
}
private void listBox2_SelectedIndexChanged(object sender, EventArgs e)
{
// Load the list of projects
cmd.CommandText =
"SELECT ProjectName FROM Projects WHERE ProjectID IN(SELECT ProjectID FROM EmployeeProject WHERE EmpId=(SELECT EmpId FROM Employee WHERE EmpName= '" +
listBox2.SelectedItem.ToString() + "')) ORDER BY ProjectID";
var rdr = cmd.ExecuteReader();
listBox1.Items.Clear();
// again, I don't want to clear, but select all those employee in listbox1 that are involved in this selected project, but can't do it because it would cause infinite recursion of these
while (rdr.Read())
{
listBox2.Items.Add(rdr.GetString(0));
}
rdr.Close();
this.AutoScroll = true;
}
So? What should I do to achieve what I want to achieve? And how would I avoid that recursion? I know this way also works what I just showed, but I don't want to clear up and show up again, (this might confuse a simple user). I want for each selection, values corresponding to that selection be selected in other listbox (without causing recursion of course!). How do I do it?
EDIT I don't know how can I select multiple items in listbox programmatically, so if you could tell that, it would be great!
There is a design pattern called Balking, I think it applies here.
http://en.wikipedia.org/wiki/Balking_pattern
The idea is to introduce an auxiliary state variable to control the operation:
private bool doesProcessing { get; set; }
private void listBox1_SelectedIndexChanging( ... )
{
// signal the beginning of processing
if ( doesProcessing )
return;
else
doesProcessing = true;
try
{
// your logic goes here
}
finally
{
// signal the end of processing
doesProcessing = false;
}
}
and the same for listBox2.
When you change the selected items of one listbox, you could temporarily disable the events on the other. For example:
// Store the event handlers in private member variables.
private System.EventHandler selectedEmployeeChanged = new System.EventHandler(this.lbEmployees_SelectedIndexChanged);
private void lbProjects_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
// Remove your event so that updating lbEmployees doesn't cause
// lbEmployees_SelectedIndexChanged to get fired.
lbEmployees.SelectedIndexChanged -= selectedEmployeeChanged;
// other event handler logic
}
finally
{
// Ensure that the handler on lbEmployees is re-added,
// even if an exception was encountered.
lbEmployees.SelectedIndexChanged += selectedEmployeeChanged;
}
}
Note: I have renamed your listBoxes (and the associated events) to be more readable. As per your description, listBox1 is now lbEmployees and listBox2 is now lbProjects.
As for programatically selecting multiple items, if you know the index for each one, you could use the ListBox.SetSelected Method. For example:
listBox1.SetSelected(1, true);
listBox1.SetSelected(3, true);
causes listBox1 to select the items at 1 and 3.
In your case, I would recomend only using the queries to get what values to select (not clearing your listboxes and then just adding back the values that should be selected). Below is my suggestion for how you would rewrite one of your handlers:
// Store the event handlers in private member variables.
private System.EventHandler selectedEmployeeChanged = new System.EventHandler(this.lbEmployees_SelectedIndexChanged);
private void lbProjects_SelectedIndexChanged(object sender, EventArgs e)
{
// Declare this outside of try so that we can close it in finally
DbDataReader reader = null;
try
{
// Remove your event so that updating lbEmployees doesn't cause
// lbEmployees_SelectedIndexChanged to get fired.
lbEmployees.SelectedIndexChanged -= selectedEmployeeChanged;
// Deselect all items in lbEmployees
lbEmployees.ClearSelected();
cmd.CommandText = "SELECT ProjectName FROM Projects WHERE ProjectID IN(SELECT ProjectID FROM EmployeeProject WHERE EmpId=(SELECT EmpId FROM Employee WHERE EmpName= '#EmpName')) ORDER BY ProjectID";
cmd.Parameters.AddWithValue("#EmpName", lbProjects.SelectedItem.ToString());
reader = cmd.ExecuteReader();
// For each row returned, find the index of the matching value
// in lbEmployees and select it.
while (rdr.Read())
{
int index = lbEmployees.FindStringExact(rdr.GetString(0));
if(index != ListBox.NoMatches)
{
lbEmployees.SetSelected(index, true);
}
}
this.AutoScroll = true;
}
finally
{
// Ensure that the reader gets closed, even if an exception ocurred
if(reader != null)
{
reader.Close();
}
// Ensure that the handler on lbEmployees is re-added,
// even if an exception was encountered.
lbEmployees.SelectedIndexChanged += selectedEmployeeChanged;
}
}
As a side note, you may want to look into using a JOIN operator in your query string, rather than multiple nested SELECTS.
You can remove the attached event to one of the controls when you are in the other, before doing any modifications.
then reattach at the end.
Have one eventMask integer variable and use the pattern below to protect your event each other.
Using a bool as suggested in another answer is enough for this scenario. However, I prefer to use an integer rather than a bool : it can handle nested and stacked events calls correctly.
It is particularly useful when I have to deal with selection/deselection events in treeviews and listviews for example.
int eventMask = 0;
void items_PropertyChanged(object sender, PropertyChangedEventArgs e) // for example...
{
if (eventMask > 0)
return;
try
{
eventMask++;
// processing
// it happens some other events can be called. Including this one.
}
finally
{
// put this in finally, so there is no lock risk
eventMask--;
}
}
The logic of the OP code (if working as OP expect) contains a problem.
Suppose you fill the two lists with all possible values.
Then, when the user clicks on one item, the second list is emptied and filled only with the item linked to the other list. But clicking between the two list could remove forever one or more item from the other list. It is better to leave the two list filled and trying to highlight the line of the corresponding items
For example (supposing ListBox.SelectionMode = SelectionMode.MultiSimple or MultiExtended)
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
........
try
{
......
// Remove the event handler, do your selection, No event on the listbox2 will be fired....
listBox2.SelectedIndexChanged -= new System.EventHandler(this.listBox2_SelectedIndexChanged);
// Do not remove the items , instead clear previous selection
listBox2.ClearSelected();
while (rdr.Read())
{
int index = listBox2.FindString(rdr.GetString(0), -1);
if(index != -1) listBox2.SetSelected(index, true));
}
....
}
finally
{
// before exit, reapply the event handler
listBox2.SelectedIndexChanged += new System.EventHandler(this.listBox2_SelectedIndexChanged);
}
}
of course you need to be sure to reapply the event, so use a try/finally block
The same approach will be valid to stop the event firing for listBox1 when you fill it in the listBox2.SelectedIndexChanged event,

c# button click queueing

I have a button click event handler with a switch case in it that controls multiple buttons in one event handler.
I need to use a queue because while one button is clicked and doing some processing, second button click won't interfere with the first button click, but added to the queue. I don't want to use .enabled=false; because it'll discard the second click completely, and I'm currently editing someone's software at work so I don't want to break things that I don't know, so what are you suggesting?
The best idea, I think, is to create a producer/consumer queue.
Another question is explaining this technique.
Basically, the idea is to have a worker thread that will consume a queue to get the job to do, while other thread produce job by queuing operation in the queue.
I did succeed this with System.Collections.Queue
The code is :
private Queue<Button> Button_Queue = new Queue<Button>();
private bool isProcessing = false;
private void Button_Click((object sender, EventArgs e){
if(isProcessing){
Button_Queue.Enqueue(this);
}
else
{
isProcessing = true;
// code here
isProcessing = false;
while(Button_Queue.Count > 0){
Button_Queue.Dequeue().PerformClick();
}
}
of course mine is slightly different from this because I need to pass some variables and my click method is modified for this.
Dirty, but simple solution.
public partial class DataRefresh : Form //DataRefresh is just "some form"
{
...
...
public DateTime ClickTime; //Time when click is processed by system
public DateTime LastExecutionRunTime = DateTime.MinValue; //Time when the all the click code finish
private void buttonDataRefresh_Click(object sender, EventArgs e)
{
ClickTime = DateTime.Now;
if (ClickTime.Subtract(LastExecutionRunTime).TotalSeconds < 5 )
{
//It will keep returning - hopefully until all events in que are satisfied
return;
}
//Long running code
//Importing whole table from remote DB
...
...
//End of the Long running code
LastExecutionRunTime = DateTime.Now;
}
}

Delay in event in code behind file

In my application I have a button to save some information. However, I would like to have a delay in the code before the last line is executed, so that the user could read the message that shows up before he gets redirected to the new page.
I know that doing this isn't at all an optimal way, but by some reasons (time, for example) I want to do it anyway.
So is it possible and if so, how could I do it?
Thanks in advance!
protected void SaveButton_Click(object sender, EventArgs e) {
// Lots of code not relevant for the problem here
Service service = new Service();
service.SaveMovie(movie);
successMessage.Visible = true;
happyMessage.Text = "The movie was successfully added, now add some genres!";
// Here I want a delay of 2 seconds before the next line is executed...
Response.Redirect(String.Format("~/Edit.aspx?id={0}", movie.MovieID), false);
}
You need to do this on the client side. One alternative is this:
Define a Javascript function in the page called redirect as so:
function redirect(url)
{
setTimeout(function(){window.location.href=url;} ,2000);
}
protected void SaveButton_Click(object sender, EventArgs e)
{
// Lots of code not relevant for the problem here
Service service = new Service();
service.SaveMovie(movie);
successMessage.Visible = true;
happyMessage.Text = "The movie was successfully added, now add some genres!";
// Here I want a delay of 2 seconds before the next line is executed...
ClientScript.RegisterStartupScript(this.GetType(),"somekey","redirect('"+String.Format("~/Edit.aspx?id={0}", movie.MovieID)+"');");
}
This will be easy if you are using Javascript. Use javascript will boost performance
Button_Click
{
string js ="<script type='text/javascript'>setTimeout(function()window.location.href="+String.Format("~/Edit.aspx?id={0}", movie.MovieID)+";} ,2000);</script>"
ScriptManager.RegisterStartupScript(Me.Page, GetType(Page), "js", js, False)
}
possible duplicate of
asp.net delay before response redirect

Categories