0

It executes @RefreshDataGrid() just fine but when I try to execute findCommand() it gives me this exception:

Exception thrown: 'System.InvalidOperationException' in System.Windows.Forms.dll Cross-thread operation not valid: Control 'dgvMySqlKBer' accessed from a thread other than the thread it was created on.

if you need more information feel free to ask, anyway here's the code. I have found that it has something to do with: this.Load += Form1_Load;

using System;
using System.Threading.Tasks;
using System.Windows.Forms;
using Discord;
using System.Media;
using System.Text.RegularExpressions;
using System.Data;
using System.ComponentModel;
using MySql.Data.MySqlClient;
using System.Linq;

namespace DiscordSongRequest
{
    public partial class Form1 : Form
    {
        string ipaddress = "localhost";
        string username = "root";
        string password = "";

        private DiscordClient client;
        SoundPlayer player = new SoundPlayer();
        Random random = new Random();
        public static readonly Regex YoutubeVideoRegex = new Regex(@"youtu(?:\.be|be\.com)/(?:.*v(?:/|=)|(?:.*/)?)([a-zA-Z0-9-_]+)", RegexOptions.IgnoreCase);

        public Form1()
        {
            this.Load += Form1_Load;
        }

        private void Form1_Load(object sender, System.EventArgs e)
        {
            Task.Factory.StartNew(() => ConnectClient());
            InitializeComponent();            
            dgvMySqlKBer.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            RefreshDataGrid();
        }

        private void RefreshDataGrid()
        {
            try
            {
                string MyConnection = "datasource=" + ipaddress + ";username=" + username + ";password=" + password + "";
                string Query = "select * from discordsongrequest.commands;";
                MySqlConnection MyConn = new MySqlConnection(MyConnection);
                MySqlCommand MyCommand = new MySqlCommand(Query, MyConn);
                MyConn.Open();
                MySqlDataAdapter MyAdapter = new MySqlDataAdapter();
                MyAdapter.SelectCommand = MyCommand;
                DataTable dTable = new DataTable();
                MyAdapter.Fill(dTable);
                dgvMySqlKBer.DataSource = dTable;            
                MyConn.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private async Task ConnectClient()
        {
            try
            {
                client = new DiscordClient();
                client.MessageCreated += async (s, e) =>
                {
                    switch (e.Message.Text)
                    {
                        case "!stop":
                            webBrowser1.Navigate("about:blank");
                            break;
                        case "!hallo":
                            findCommand(e.Message.Text);
                            player.Play();
                            break;                        
                        case "!play":
                            break;
                        case "!random":
                            int randomNumber = random.Next(0, 1000);
                            await client.SendMessage(e.Message.Channel, "Random! You roll a: " + Convert.ToString(randomNumber) + ".");
                            break;
                        case "!coin":
                            randomNumber = random.Next(0, 2);
                            if (randomNumber == 0)
                            {
                                await client.SendMessage(e.Message.Channel, "Coinflip! it lands on: Heads.");
                            }
                            else
                            {
                                await client.SendMessage(e.Message.Channel, "Coinflip! it lands on: Tails.");
                            }
                            break;
                        default:
                            if (e.Message.Text.StartsWith("!play"))
                            {
                                string l = e.Message.Text;
                                l = (l.StartsWith("!play")) ? l.Substring(6) : l;
                                checkForLink(l);
                            }
                            break;
                    }
                };
                await client.Connect("username", "password");
                await client.AcceptInvite("invitecode");
            }

            catch
            {
            }
        }

        private void checkForLink(string l)
        {
            try
            {
                Match youtubeMatch = YoutubeVideoRegex.Match(l);
                if (youtubeMatch.Success)
                {
                    Uri uri = new Uri(l);
                    webBrowser1.Url = uri;
                }
            }

            catch
            {
            }
        }

        private void findCommand(string command)
        {            
            string MyConnection = "datasource=" + ipaddress + ";username=" + username + ";password=" + password + "";
            string Query = "select * from discordsongrequest.commands where command = '" + command + "';";
            MySqlConnection MyConn = new MySqlConnection(MyConnection);
            MySqlCommand MyCommand = new MySqlCommand(Query, MyConn);
            MyConn.Open();
            MySqlDataAdapter MyAdapter = new MySqlDataAdapter();
            MyAdapter.SelectCommand = MyCommand;
            DataTable dTable = new DataTable();
            MyAdapter.Fill(dTable);
            dgvMySqlKBer.DataSource = dTable;
            MyConn.Close();
        }

    }
}
NASSER
  • 5,900
  • 7
  • 38
  • 57
xLuckless
  • 1
  • 2

1 Answers1

-2

Have a look here: How to: Manipulate Controls from Threads

The dgvMySqlKBer object was created in the main events thread, and you're trying to access it from within another thread which is not a valid operation. You need to call invoke in that object and pass it an Action.

    private void findCommand(string command)
    {            
        string MyConnection = "datasource=" + ipaddress + ";username=" + username + ";password=" + password + "";
        string Query = "select * from discordsongrequest.commands where command = '" + command + "';";
        MySqlConnection MyConn = new MySqlConnection(MyConnection);
        MySqlCommand MyCommand = new MySqlCommand(Query, MyConn);
        MyConn.Open();
        MySqlDataAdapter MyAdapter = new MySqlDataAdapter();
        MyAdapter.SelectCommand = MyCommand;
        DataTable dTable = new DataTable();
        MyAdapter.Fill(dTable);

        dgvMySqlKBer.Invoke((MethodInvoker)delegate
        {
            dgvMySqlKBer.DataSource = dTable;
        });         

        dgvMySqlKBer.DataSource = dTable;
        MyConn.Close();
    }
MeTitus
  • 3,390
  • 2
  • 25
  • 49
  • Please **stop** flagging this post for moderator attention, and asking a moderator to remove the downvote from the post. Moderators cannot alter votes. – Matt Mar 15 '16 at 13:24
  • Well than something is wrong with the process isn't it? – MeTitus Mar 15 '16 at 15:05
  • What makes you think that? Stack Overflow allows users to vote as they please (providing the voting is not fraudulent or targeted; and neither apply here). Voting is supposed to represent the consensus of the community; not the feeling of one moderator. If we allowed moderators to invalidate votes as they pleased, we would lose this perspective. – Matt Mar 15 '16 at 15:11
  • You have a point, but how can this answer help anyone if it has a negative rating when it is the right one? If you follow the comments you'll see that I updated the answer and the rating was kept negative... anyways I get what you're saying. – MeTitus Mar 15 '16 at 16:09
  • @Marco this answer is *wrong*. You *don't* need `BeginInvoke` (Invoke blocks) when you use `async/await`. The problem occurs because the OP is trying to access the control from inside the background thread. The data access code is trying to modify the UI, which is a bad design anyway. The code should be refactored to *return* the results to an asynchronous event handler which can update the UI – Panagiotis Kanavos Oct 31 '17 at 12:12
  • @PanagiotisKanavos I know exactly why the error is happening and the answer is right. Did you even read the answer properly? BeginInvoke is blocking and so what? You need to access of work for the thread which own the context of the object hes trying to change... what a waste of my time... – MeTitus Nov 12 '17 at 10:45
  • @Marco I'm not the only downvoter. I'm the one that bothered to explain. This answer might have been correct 10 years ago. It's wrong since 2010, definitely since 2012 when `async/await`. were introduced. The framework now has built-in mechanisms for returnign to the original thread or reporting progress. What you posted here is the equivalent of proposing code generators for collections and casting from `object` instead of using generic containers – Panagiotis Kanavos Nov 13 '17 at 08:08
  • @Marco perhaps you should check [Async in 4.5: Enabling Progress and Cancellation in Async APIs](https://blogs.msdn.microsoft.com/dotnet/2012/06/06/async-in-4-5-enabling-progress-and-cancellation-in-async-apis/) for an example of progress reporting – Panagiotis Kanavos Nov 13 '17 at 08:09
  • @Marco finally, posting an answer when there are so many duplicates doesn't help at all. It increases the noise and makes it *harder* for people to find a correct answer. The duplicate to this question already includes the solution you posted (from 2008), a detailed description of the UI threading mechanism *and* an update on `async/await` several years later. – Panagiotis Kanavos Nov 13 '17 at 08:16
  • I'm quite comfortable with async/await mechanisms, been using it since it was relased. Thanks for pointing that out – MeTitus Nov 15 '17 at 09:35