I currently am working on a small test project with the YouTube API.
What I am trying to achieve is pretty simple : I do a search request with the API get the title and video ID and I put those in a DataTable.
From there I want to make a button out of each result and add these to a FlowLayoutPanel so what I figured was use a foreach loop. But the issue that's presenting itself here is when I got over 100+ results it seems to throw errors (I guess windows forms doesn't like making 100+ buttons)
What I want to know is can I make my code more efficient and can I for example add 2 buttons below to show the "next" and "previous" 100 results. So it will only load 100 at a time.
Below is my code it may be a bit messy since I am pretty new to c#.
This is the button I use to start the search.
private void Youtube_Search_Video_Button_Click(object sender, EventArgs e)
{
string Search_Vid = Youtube_SearchVideo_Box.Text;
if (Youtube_SearchVideo_Box.Text == "Search video" || Youtube_SearchVideo_Box.Text == "")
{
Youtube_SearchVideo_Box.Text = "Search video";
}
if (Search_Vid != null && Search_Vid != "Search video" && Search_Vid != Last_Search_Vid)
{
Last_Search_Vid = Youtube_SearchVideo_Box.Text;
search_results_vids.Clear();
if (search_results_vids.Columns.Count.Equals(0)) {
search_results_vids.Columns.Add("VideoTitle");
search_results_vids.Columns.Add("VideoID");
}
flowLayoutPanel1.Controls.Clear();
toolStripStatusLabel1.Text = "Status : Searching...";
backgroundWorker1.RunWorkerAsync();
}
}
Which starts the backgroundworker below. (Oh and of course the datatable creating before that.)
public DataTable search_results_vids = new DataTable();
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
YouTubeService youtube = new YouTubeService(new BaseClientService.Initializer()
{
ApplicationName = this.GetType().ToString(),
ApiKey = "MyApiKeY",
});
var nextPageToken = "";
while (nextPageToken != null)
{
var listRequest = youtube.Search.List("snippet");
listRequest.Q = Youtube_SearchVideo_Box.Text;
listRequest.MaxResults = 50;
listRequest.Type = "video";
listRequest.PageToken = nextPageToken;
var resp = listRequest.Execute();
List<string> videos = new List<string>();
foreach (SearchResult result in resp.Items)
{
switch (result.Id.Kind)
{
case "youtube#video":
object[] newsearchresult = { result.Snippet.Title, result.Id.VideoId};
search_results_vids.Rows.Add(newsearchresult);
break;
}
}
nextPageToken = resp.NextPageToken;
}
}
And when it finishes.
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
foreach (DataRow row in search_results_vids.Rows)
{
Button button = new Button();
button.Text = row["VideoTitle"].ToString();
if (button.Text.Length >= 35)
{
button.Text.Remove(button.Text.Length - (button.Text.Length - 35));
}
button.Tag = row["VideoID"];
button.TextImageRelation = TextImageRelation.ImageBeforeText;
button.FlatStyle = FlatStyle.Flat;
button.ForeColor = Color.LightSteelBlue;
button.BackColor = Color.SteelBlue;
button.Width = (flowLayoutPanel1.Width - 120);
button.TextAlign = ContentAlignment.MiddleLeft;
button.Height = 35;
button.Font = new Font(button.Font.FontFamily, 10);
flowLayoutPanel1.Controls.Add(button);
}
toolStripStatusLabel1.Text = "Status : Listing Videos, Please Wait...";
toolStripStatusLabel2.Text = "Results : " + search_results_vids.Rows.Count.ToString();
}
I've tried adding the Foreach loop into the DoWork part of the backgroundworker but then it seems to skip it all together. Any help is very welcome and if I did anything wrong please let me know (Still learning!)
Edit : To clarify it's the button creation part I am stuck at. Listing the items from the table to a listview works fine. All the button settings seem to have to do with the loading time of them. So that's why I want to try an approach where I load only 100 per "page" from the DataTable. I only have no idea how to approach this.
Yes You can Add Buttons in the Same Loop(backgroundWorker1_DoWork) ,Just Make Sure that Adding/Changing UI should be in different Thread ...Otherwise You Would get Cross-Thread Exception.
so One Way to do is
Action actUI = ()=>{
Button button = new Button();
button.Text = get Data from newsearchresult ;
if (button.Text.Length >= 35)
{
button.Text.Remove(button.Text.Length - (button.Text.Length - 35));
}
button.Tag = get Data from newsearchresult ;;
button.TextImageRelation = TextImageRelation.ImageBeforeText;
button.FlatStyle = FlatStyle.Flat;
button.ForeColor = Color.LightSteelBlue;
button.BackColor = Color.SteelBlue;
button.Width = (flowLayoutPanel1.Width - 120);
button.TextAlign = ContentAlignment.MiddleLeft;
button.Height = 35;
button.Font = new Font(button.Font.FontFamily, 10);
flowLayoutPanel1.Controls.Add(button);
};
if(flowLayoutPanel1.InvokeRequired)
flowLayoutPanel1.BeginInvoke(actUI);
else
flowLayoutPanel1.Invoke(actUI);
I think you should be looking into bringing your results in pages.
YouTube API - Pagination
Related
I have a Column in my data source named Status. Based on this field, I want to change the Button's text:
For example, if Status is:
Stop, change the Button's text to Start
Start, change the Button's text to Stop
Please review what I have tried .
This how I bind the grid and create the DataGridViewButtonColumn:
var tasks = await TaskDetail.GetSelectedProjectTask(id);
var taskList = new BindingList<TaskDetailListModel>(tasks);
grdTask.DataSource = taskList;
var btnStart = new DataGridViewButtonColumn();
btnStart.Name = "btnAction";
btnStart.HeaderText = "Start";
btnStart.Text = "Start";
btnStart.UseColumnTextForButtonValue = true;
grdTask.Columns.Add(btnStart);
I want that before the data is displayed in the grid, the Button's text should be renamed according to the value of the Status Column:
private void grdTask_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
var row = (TaskDetailListModel)grdTask.Rows[e.RowIndex].DataBoundItem;
if (row.Status == TasksStatus.Start.ToString())
{
var btnStop = new DataGridViewButtonColumn();
btnStop.Name = "btnStop";
btnStop.HeaderText = "Stop";
btnStop.Text = "Stop";
btnStop.UseColumnTextForButtonValue = true;
grdTask.Columns.Add(btnStop);
}
else
{
var btnStart = new DataGridViewButtonColumn();
btnStart.Name = "btnStart";
btnStart.HeaderText = "Start";
btnStart.Text = "Start";
btnStart.UseColumnTextForButtonValue = true;
grdTask.Columns.Add(btnStart);
}
}
But it is not working as expected...
Also please review the attached Image here to have clear understanding of my problem.
i am facing a trouble for few days. I had create a dynamic buttons at runtime but it will disappear on the next startup. please help. below is my coding.
private void button1_Click(object sender, EventArgs e)
{
createNewTable createTable = new createNewTable();
DialogResult dResult = createTable.ShowDialog();
string table_name = "";
if (dResult == DialogResult.OK)
{
table_name = createTable.tableName;
createTable.Dispose();
}
else if (dResult == DialogResult.Cancel)
{
createTable.Dispose();
}
if(table_name != string.Empty){
Button textbox = new Button();
textbox.Name = "btn_" + table_name;
textbox.Text = table_name;
textbox.Height = 55;
textbox.Width = 123;
textbox.MouseDown += new MouseEventHandler(textbox_MouseDown);
textbox.MouseMove += new MouseEventHandler(textbox_MouseMove);
textbox.MouseUp += new MouseEventHandler(textbox_MouseUp);
textbox.ContextMenuStrip = contextMenuStrip1;
this.Controls.Add(textbox);
}
}
i had searched some info like using XMLSerialize/application settings but it dont provided any sample for me how to add dynamic button using XMLSerialize. please help..
I am trying to enable my links to be opened in a web browser.
Everything works fine with the delegate in the for loop but inside the eventGen() method I tried to obtain the name of the link clicked in which one link brings the string nameOfLink as ...
"System.Windows.Forms.LinkLabel, Text: Quora For Programmers"
on using an if statement to verify the selected name and open the link all the if statements are always skipped even if i change the text to
nameOfLink.Equals("Quora For Programmers");
namespace VisitedSites
{
public partial class frmRecentlyVisitedSites : Form
{
// Create an array of Link labels
LinkLabel[] sites = new LinkLabel[3];
// Create links with the tool tips
LinkLabel lnkQuora = new LinkLabel();
ToolTip quora = new ToolTip();
// Create links with the tool tips
LinkLabel lnkIndeed = new LinkLabel();
ToolTip indeed = new ToolTip();
// Create links with the tool tips
LinkLabel lnkHackerRank = new LinkLabel();
ToolTip hackerRank = new ToolTip();
public frmRecentlyVisitedSites()
{
InitializeComponent();
}
private void frmRecentlyVisitedSites_Load(object sender, EventArgs e)
{
// Populate the array with links
sites[0] = lnkQuora;
quora.SetToolTip(lnkQuora, "Quora For Questions!");
sites[1] = lnkIndeed;
indeed.SetToolTip(lnkIndeed, "Qualified For Jobs!");
sites[2] = lnkHackerRank;
hackerRank.SetToolTip(lnkHackerRank, "Comfortable Coding?");
// Configure the LinkLabel's properties.
this.lnkQuora.Location = new System.Drawing.Point(37, 36);
this.lnkQuora.AutoSize = true;
this.lnkQuora.Text = "Quora For Programmers";
// Configure the LinkLabel's properties.
this.lnkIndeed.Location = new System.Drawing.Point(37, 56);
this.lnkIndeed.AutoSize = true;
this.lnkIndeed.Text = "Indeed For The Skilled";
// Configure the LinkLabel's properties.
this.lnkHackerRank.Location = new System.Drawing.Point(37, 76);
this.lnkHackerRank.AutoSize = true;
this.lnkHackerRank.Text = "Hacker Rank For The Robust";
for (int i = 0; i < sites.Length; i++)
{
this.Controls.Add(sites[i]);
sites[i].LinkClicked += new LinkLabelLinkClickedEventHandler(EventGen);
}
}
private void EventGen(object sender, LinkLabelLinkClickedEventArgs e)
{
// Determine the name of the link
string nameOfLink = sender.ToString();
// process the link depending on the name
if(nameOfLink.Equals("System.Windows.Forms.LinkLabel, Text:Quora For Programmers", StringComparison.InvariantCultureIgnoreCase))
{
lnkQuora.LinkVisited = true;
System.Diagnostics.Process.Start("https://www.quora.com/");
}
else if(nameOfLink.Equals("System.Windows.Forms.LinkLabel, Text:Indeed For The Skilled", StringComparison.InvariantCultureIgnoreCase))
{
lnkQuora.LinkVisited = true;
System.Diagnostics.Process.Start("https://www.indeed.com/");
}
else if(nameOfLink.Equals("System.Windows.Forms.LinkLabel, Text:Hacker Rank For The Robust", StringComparison.InvariantCultureIgnoreCase))
{
lnkQuora.LinkVisited = true;
System.Diagnostics.Process.Start("https://www.hackerrank.com/");
}
}
}
}
Just tried your code, you are missing one space
is
System.Windows.Forms.LinkLabel, Text: Quora For Programmers
instead of
System.Windows.Forms.LinkLabel, Text:Quora For Programmers
why not add the links, e.g. "https://www.quora.com/" to the linkdata like link.LinkData = "https://www.quora.com/", and then open that link using Process.Start(e.Link.LinkData as string)?
I'm currently working in VS 2012.
.NET 4.5 and working on an mmc snap-in. (i know right?!)
so i followed this topic:
Is there a simple way to implement a Checked Combobox in WinForms
as i want something similar to the scheduled task manager.
But that solution does not seem to work for me.
the listview pops up but when i try to click on a checkbox in my listview.
It gives me a big middle finger and closes my dropdown.
is there any way i can suppress the combobox's "focus lost" close event?
i can, not hide the list but then it never hides.
For Example:
// designer class
//
// comboBox1
//
this.comboBox1.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
this.comboBox1.DropDownHeight = 1;
this.comboBox1.DropDownWidth = 1;
this.comboBox1.FormattingEnabled = true;
this.comboBox1.IntegralHeight = false;
this.comboBox1.Location = new System.Drawing.Point(256, 371);
this.comboBox1.Name = "comboBox1";
this.comboBox1.Size = new System.Drawing.Size(238, 21);
this.comboBox1.TabIndex = 5;
this.comboBox1.DropDown += new System.EventHandler(this.comboBox1_DropDown);
this.comboBox1.DropDownClosed += new System.EventHandler(this.comboBox1_DropDownClosed);
//
// lstWeekDays
//
this.lstWeekDays.CheckBoxes = true;
this.lstWeekDays.Location = new System.Drawing.Point(50, 63);
this.lstWeekDays.Name = "lstWeekDays";
this.lstWeekDays.Size = new System.Drawing.Size(263, 97);
this.lstWeekDays.TabIndex = 13;
this.lstWeekDays.Tag = "lstlstWeekDays";
this.lstWeekDays.UseCompatibleStateImageBehavior = false;
this.lstWeekDays.View = System.Windows.Forms.View.SmallIcon;
this.lstWeekDays.Visible = false;
// Code behind
public Form1()
{
InitializeComponent();
this.lstWeekDays.Items.Add("Monday");
this.lstWeekDays.Items.Add("Tuesday");
this.lstWeekDays.Items.Add("Wednesday");
this.lstWeekDays.Items.Add("Thursday");
this.lstWeekDays.Items.Add("Friday");
this.lstWeekDays.Items.Add("Saturday");
this.lstWeekDays.Items.Add("Sunday");
}
private void comboBox1_DropDown(object sender, EventArgs e)
{
lstWeekDays.Visible = true;
}
private void comboBox1_DropDownClosed(object sender, EventArgs e)
{
lstWeekDays.Visible = false;
}
Add the checkboxes to this list instead of the panel.
Ok The problem is I have a grid that I need to have paging on it with pages shown as numbers
I want to add two link button to the paging section to alow user to navigate to next page prev page
Here is my code
protected void CustomerGridView_RowCreated(object sender, GridViewRowEventArgs e)
{
var grid = sender as GridView
if (e.Row.RowType == DataControlRowType.Pager)
{
var prvLink = new LinkButton();
prvLink.Text = "<";
prvLink.CommandName = "Page";
prvLink.CommandArgument = "Prev";
prvLink.EnableViewState = true;
var nextLink = new LinkButton();
nextLink.Text = ">";
nextLink.CommandName = "Page";
nextLink.CommandArgument = "Next";
nextLink.EnableViewState = true;
var prvCell = new TableCell();
var nextCell = new TableCell();
prvCell.Controls.Add(prvLink);
nextCell.Controls.Add(nextLink);
Table pagerTable = e.Row.Controls[0].Controls[0] as Table;
TableRow row = pagerTable.Rows[0];
row.Cells.AddAt(0, prvCell);
row.Cells.AddAt(row.Cells.Count, nextCell);
if (grid.PageIndex == 0)
{
prvCell.Enabled = false;
}
if (grid.PageIndex == grid.PageCount - 1)
{
nextCell.Enabled = false;
}
}
}
its perfectly working and users are able to navigate back and forward (and I can see grid RowCommand event getting fired)
The problem is I do not want to put the code inside my page (to make my page tiny and put the responsibility to an other class )
here is my class
public class GridStyler
{
private GridView _grid;
public GridStyler(GridView grid)
{
_grid = grid;
}
public void AddNextPreviousOnPager()
{
_grid.RowCreated += _grid_RowCreated;
}
void _grid_RowCreated(object sender, GridViewRowEventArgs e)
{
var grid = sender as GridView;
if (e.Row.RowType == DataControlRowType.Pager)
{
var prvLink = new LinkButton();
prvLink.Text = "<";
prvLink.CommandName = "Page";
prvLink.CommandArgument = "Prev";
prvLink.EnableViewState = true;
var nextLink = new LinkButton();
nextLink.Text = ">";
nextLink.CommandName = "Page";
nextLink.CommandArgument = "Next";
nextLink.EnableViewState = true;
var prvCell = new TableCell();
var nextCell = new TableCell();
prvCell.Controls.Add(prvLink);
nextCell.Controls.Add(nextLink);
Table pagerTable = e.Row.Controls[0].Controls[0] as Table;
TableRow row = pagerTable.Rows[0];
row.Cells.AddAt(0, prvCell);
row.Cells.AddAt(row.Cells.Count, nextCell);
if (grid.PageIndex == 0)
{
prvCell.Enabled = false;
}
if (grid.PageIndex == grid.PageCount - 1)
{
nextCell.Enabled = false;
}
}
}
}
then I should be able to call a code like that in my page load and it should create the link buttons and response to click of them
var g = new GridStyler(CustomerGridView);
g.AddNextPreviousOnPager();
what happens is the link buttons are created just fine but when user clicks them page get refreshed but RowCommand never get fired (they get fired of course when user clicks other buttons but not this two dynamically created buttons)
Any suggestion is really appreciated