0

我有一个使用 SqlDependency 在分离线程池中运行的 Windows 应用程序,该应用程序表示一个日志监视器 UI,它获取添加到数据库中特定表中的最新行并在 DataGridView 中查看它。您可以从此LINK查看应用程序源代码,或遵循此脚本。

    const string tableName = "OutgoingLog";
    const string statusMessage = "{0} changes have occurred.";
    int changeCount = 0;

    private static DataSet dataToWatch = null;
    private static SqlConnection connection = null;
    private static SqlCommand command = null;

    public frmMain()
    {
        InitializeComponent();
    }

    private bool CanRequestNotifications()
    {
        // In order to use the callback feature of the
        // SqlDependency, the application must have
        // the SqlClientPermission permission.
        try
        {
            SqlClientPermission perm = new SqlClientPermission(PermissionState.Unrestricted);

            perm.Demand();

            return true;
        }
        catch
        {
            return false;
        }
    }

    private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
    {
        // This event will occur on a thread pool thread.
        // Updating the UI from a worker thread is not permitted.
        // The following code checks to see if it is safe to
        // update the UI.
        ISynchronizeInvoke i = (ISynchronizeInvoke)this;

        // If InvokeRequired returns True, the code
        // is executing on a worker thread.
        if (i.InvokeRequired)
        {
            // Create a delegate to perform the thread switch.
            OnChangeEventHandler tempDelegate = new OnChangeEventHandler(dependency_OnChange);

            object[] args = { sender, e };

            // Marshal the data from the worker thread
            // to the UI thread.
            i.BeginInvoke(tempDelegate, args);

            return;
        }

        // Remove the handler, since it is only good
        // for a single notification.
        SqlDependency dependency = (SqlDependency)sender;

        dependency.OnChange -= dependency_OnChange;

        // At this point, the code is executing on the
        // UI thread, so it is safe to update the UI.
        ++changeCount;
        lblChanges.Text = String.Format(statusMessage, changeCount);

        // Reload the dataset that is bound to the grid.
        GetData();
    }

    AutoResetEvent running = new AutoResetEvent(true);

    private void GetData()
    {
        // Start the retrieval of data on another thread to let the UI thread free
        ThreadPool.QueueUserWorkItem(o =>
        {
            running.WaitOne();

            // Empty the dataset so that there is only
            // one batch of data displayed.
            dataToWatch.Clear();

            // Make sure the command object does not already have
            // a notification object associated with it.
            command.Notification = null;

            // Create and bind the SqlDependency object
            // to the command object.
            SqlDependency dependency = new SqlDependency(command);

            dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);

            using (SqlDataAdapter adapter = new SqlDataAdapter(command))
            {
                adapter.Fill(dataToWatch, tableName);



                try
                {
                    running.Set();
                }
                finally
                {
                    // Update the UI
                    dgv.Invoke(new Action(() =>
                    {
                        dgv.DataSource = dataToWatch;
                        dgv.DataMember = tableName;

                        //dgv.FirstDisplayedScrollingRowIndex = dgv.Rows.Count - 1;
                    }));
                }


            }
        });
    }

    private void btnAction_Click(object sender, EventArgs e)
    {
        changeCount = 0;
        lblChanges.Text = String.Format(statusMessage, changeCount);

        // Remove any existing dependency connection, then create a new one.
        SqlDependency.Stop("Server=.; Database=SMS_Tank_Log;UID=sa;PWD=hana;MultipleActiveResultSets=True");
        SqlDependency.Start("Server=.; Database=SMS_Tank_Log;UID=sa;PWD=hana;MultipleActiveResultSets=True");

        if (connection == null)
        {
            connection = new SqlConnection("Server=.; Database=SMS_Tank_Log;UID=sa;PWD=hana;MultipleActiveResultSets=True");

        }

        if (command == null)
        {
            command = new SqlCommand("select * from OutgoingLog", connection);

            //SqlParameter prm =
            //    new SqlParameter("@Quantity", SqlDbType.Int);
            //prm.Direction = ParameterDirection.Input;
            //prm.DbType = DbType.Int32;
            //prm.Value = 100;
            //command.Parameters.Add(prm);
        }

        if (dataToWatch == null)
        {
            dataToWatch = new DataSet();
        }

        GetData();
    }

    private void frmMain_Load(object sender, EventArgs e)
    {
        btnAction.Enabled = CanRequestNotifications();
    }

    private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
    {
        SqlDependency.Stop("Server=.; Database=SMS_Tank_Log;UID=sa;PWD=hana;MultipleActiveResultSets=True");
    }

问题: 我有很多错误情况,(第一条评论中的图片)

(No. 1) : 我得到了这个错误对话框,我不知道它的原因。

(第 2 名):我的网格视图中什么也没有(没有错误,也没有数据)。

(第 3 名):虽然表格有行,但我只有列名,没有行。

我需要帮助。

4

1 回答 1

0

我可能错了,但是DataSet似乎没有通知功能,因此如果您在背后更改它, DataGridView可能会感到惊讶。

您可以尝试通过首先将其设置为 null 来明确显示您正在更改数据源:

dgv.DataSource = null;
dgv.DataSource = dataToWatch;
dgv.DataMember = tableName;

值得一试...

于 2013-06-11T19:40:33.603 回答