问题
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.
回答1:
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);
回答2:
I think you should be looking into bringing your results in pages.
YouTube API - Pagination
来源:https://stackoverflow.com/questions/35763971/c-sharp-net-youtube-v3-api-issue-listing-items-to-control