2013年2月25日星期一

C#中实现文本框的滚动条自动滚到最底端



      1、配置textBox的Multiline属性为true;
2、配置textBox的ScrollBars属性为Vertical,实现纵向滚动条;
3、然后如下语句实现自己滚动:

       private void textBox3_TextChanged_1(object sender, EventArgs e)
        {
            textBox3.SelectionStart = textBox3.Text.Length;
            textBox3.ScrollToCaret();
        }

Launching a process and displaying its standard output



Sample Image - LaunchProcess.png

Introduction

I wanted to launch a script from a Windows Form application and display the standard output in a text box as the process was running.  Surely you're not surprised to learn that multithreading is involved.  It turns out you'll have at least four threads running to do this simple task.  To keep things simple and sane, I've reused code from other another source, so I must first give credit to the MSDN article "Give Your .NET-based Application a Fast and Responsive UI with Multiple Threads"  by I.D. Griffiths.  I highly suggest reading this article for more background on multithreading in Windows Forms applications.  Thanks also to Chad Christensen for his suggestions in using a RichTextBox.

Creating a class to call a process

A script or executable can be run using System.Diagnostics.Process.  The string FileName is set to the executable (e.g. perl.exe, Run.bat, ConsoleApplication.exe).  The string Arguments is set to the command-line arguments for that executable (e.g. perlscript.pl, filename1.txt filename2.txt, etc).  The following code will start that executable.
    Process process = new Process();
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;
    process.StartInfo.CreateNoWindow = true;
    process.StartInfo.FileName = FileName;
    process.StartInfo.Arguments = Arguments;
    process.StartInfo.WorkingDirectory = WorkingDirectory;
    process.Start();
Notice that the standard output and standard error have both been redirected.  There are two StreamReaders in the Process class that can be used to read the output: Process.StandardOutput andProcess.StandardError.  Often, the output is not read until after the process has finished, as in the following:
    string output = process.StandardOutput.ReadToEnd();
Reading to the end will not work for this application, since we want to read the data as the process is running.

Multiple threads

The solution is to use multiple threads.  One thread is dedicated to running the process and two more threads are dedicated to reading the standard error and standard output.  This is mentioned in MSDNdocumentation.  Each of these two threads will run a simple function that sits in a loop reading from the stream until the stream is closed.
    void ReadStdOut()
    {
        string str;
        while ((str = process.StandardOutput.ReadLine()) != null)
        {
            // do something with str
        }
    }
After each line is read into str, we would like to notify a windows form to display the text.  Raising an event is probably the best way to accomplish this.  For every new line of text received (on either StandardOutput or StandardError) an event will be raised.  A windows form class can subscribe to these events and update a text box.  Simple, but it won't quite work without some additional work.

Important rule of windows forms

There is an important rule of windows forms and multithreading.  Controls are (almost entirely) not thread safe.  This means that an event raised from any thread other than the UI Thread cannot use methods or properties of a control.  There are a few methods guaranteed to be safe including Control.Invoke and Control.BeginInvoke.  These methods are used to run a function on the UI thread.
Thankfully, we can inherit from the class AsyncOperation (written by I.D. Griffiths from the above mentioned MSDN article) to solve several problems.  First, this class allows us to raise an event on a UI thread of a hosting or target control.  The above function becomes:
    public delegate void DataReceivedHandler(object sender,
        DataReceivedEventArgs e);

    public event DataReceivedHandler StdOutReceived;

    void ReadStdOut()
    {
        string str;
        while ((str = process.StandardOutput.ReadLine()) != null)
        {
            FireAsync(StdOutReceived, this, new DataReceivedEventArgs(str));
        }
    }
FireAsync is a method provided by the class AsyncOperation.  It raises an event (or more specifically invokes any delegate) on the UI thread of a form or control.  StdOutReceived is the event that will be raised.  DataReceivedEventArgs is a class derived from EventArgs that has a single string containing the text to be displayed (its definition is not shown here for brevity).
The second thing AsyncOperation provides is a method of canceling a process.  Let's take a look at that class in more detail.

Inheriting from AsyncOperation

AsyncOperation is an abstract base class that assists in creating cancelable worker threads that can fire events back on a UI control (or form).  It provides two main methods that are called by a form class: Start() andCancel().
AsyncOperation requires that one method be overridden: DoWork(). This method is called when the Start() method is called.  As the method runs, it is expected to watch for a flag CancelRequested that is set from a call to Cancel().  If the flag is true, the method should acknowledge the cancel and return.
The implementation of DoWork() is as follows:
    void protected override void DoWork()()
    {
        // Start a new process for the cmd
        Process process = new Process();
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.RedirectStandardError = true;
        process.StartInfo.CreateNoWindow = true;
        process.StartInfo.FileName = FileName;
        process.StartInfo.Arguments = Arguments;
        process.StartInfo.WorkingDirectory = WorkingDirectory;
        process.Start();

        
        // Invoke stdOut and stdErr readers - each
        // has its own thread to guarantee that they aren't
        // blocked by, or cause a block to, the actual
        // process running (or the gui).
        new MethodInvoker(ReadStdOut).BeginInvoke(null, null);
        new MethodInvoker(ReadStdErr).BeginInvoke(null, null);

        // Wait for the process to end, or cancel it
        while (! process.HasExited)
        {
            Thread.Sleep(SleepTime); // sleep
            if (CancelRequested)
            {
                // Not a very nice way to end a process,
                // but effective.
                process.Kill();
                AcknowledgeCancel();
            }
        }

    }
The methods DoWork()ReadStdOut(), and ReadStdErr(), the properties FileName and Arguments, and the events StdOutReceived and StdErrReceived are all added to a class ProcessCaller which derives from AsyncOperation.  Both classes can be downloaded as part of the zipfile at the top of the page.

The form

As shown in the picture above, the form is quite simple.  It consists of a rich text box to show the standard output and standard input, a button to run a process (Ok), and a button to cancel the process (Cancel).
The Ok button calls the Start() method on ProcessCaller and the Cancel button calls the Cancel() method.  The events StdOutRecieved and StdErrReceived are handled by the following function:
    private void writeStreamInfo(object sender, DataReceivedEventArgs e)
    {
        this.richTextBox1.AppendText(e.Text + Environment.NewLine);
    }

Improvements

Adding a progress bar to the form is one nice improvement for the user interface.  Of course, you have to know the progress of the program being run.  One option is to have the script tell you explicitly in the standard output with lines such as: "Percent completion = 30".  Your "writeStreamInfo" function would filter those lines and update a progress bar.
Standard Error can be displayed in red or some other color (or in a separate rich text box) to highlight any errors found.  At the end of the process, a dialog could be displayed with a list of all errors.
Providing support for standard input shouldn't be too difficult, but integrating it with the windows form may be tough.  Perhaps a separate single-line text box whose contents are sent to the standard input stream through a method on ProcessCaller.
These are just a few ideas of improvements you can make.

Conclusion

Using the class AsyncOperation reduced the design complexity of this program.  Hopefully, the class ProcessCaller will provide you just as much help in reducing the complexity of running scripts and monitoring the output.

Revision History

  • 2003-Jul-31 : Original Post
  • 2003-Aug-05 : Fixed some spelling / grammatical mistakes (oops)
 

Launching a process and displaying its standard output



Sample Image - LaunchProcess.png

Introduction

I wanted to launch a script from a Windows Form application and display the standard output in a text box as the process was running.  Surely you're not surprised to learn that multithreading is involved.  It turns out you'll have at least four threads running to do this simple task.  To keep things simple and sane, I've reused code from other another source, so I must first give credit to the MSDN article "Give Your .NET-based Application a Fast and Responsive UI with Multiple Threads"  by I.D. Griffiths.  I highly suggest reading this article for more background on multithreading in Windows Forms applications.  Thanks also to Chad Christensen for his suggestions in using a RichTextBox.

Creating a class to call a process

A script or executable can be run using System.Diagnostics.Process.  The string FileName is set to the executable (e.g. perl.exe, Run.bat, ConsoleApplication.exe).  The string Arguments is set to the command-line arguments for that executable (e.g. perlscript.pl, filename1.txt filename2.txt, etc).  The following code will start that executable.
    Process process = new Process();
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;
    process.StartInfo.CreateNoWindow = true;
    process.StartInfo.FileName = FileName;
    process.StartInfo.Arguments = Arguments;
    process.StartInfo.WorkingDirectory = WorkingDirectory;
    process.Start();
Notice that the standard output and standard error have both been redirected.  There are two StreamReaders in the Process class that can be used to read the output: Process.StandardOutput andProcess.StandardError.  Often, the output is not read until after the process has finished, as in the following:
    string output = process.StandardOutput.ReadToEnd();
Reading to the end will not work for this application, since we want to read the data as the process is running.

Multiple threads

The solution is to use multiple threads.  One thread is dedicated to running the process and two more threads are dedicated to reading the standard error and standard output.  This is mentioned in MSDNdocumentation.  Each of these two threads will run a simple function that sits in a loop reading from the stream until the stream is closed.
    void ReadStdOut()
    {
        string str;
        while ((str = process.StandardOutput.ReadLine()) != null)
        {
            // do something with str
        }
    }
After each line is read into str, we would like to notify a windows form to display the text.  Raising an event is probably the best way to accomplish this.  For every new line of text received (on either StandardOutput or StandardError) an event will be raised.  A windows form class can subscribe to these events and update a text box.  Simple, but it won't quite work without some additional work.

Important rule of windows forms

There is an important rule of windows forms and multithreading.  Controls are (almost entirely) not thread safe.  This means that an event raised from any thread other than the UI Thread cannot use methods or properties of a control.  There are a few methods guaranteed to be safe including Control.Invoke and Control.BeginInvoke.  These methods are used to run a function on the UI thread.
Thankfully, we can inherit from the class AsyncOperation (written by I.D. Griffiths from the above mentioned MSDN article) to solve several problems.  First, this class allows us to raise an event on a UI thread of a hosting or target control.  The above function becomes:
    public delegate void DataReceivedHandler(object sender,
        DataReceivedEventArgs e);

    public event DataReceivedHandler StdOutReceived;

    void ReadStdOut()
    {
        string str;
        while ((str = process.StandardOutput.ReadLine()) != null)
        {
            FireAsync(StdOutReceived, this, new DataReceivedEventArgs(str));
        }
    }
FireAsync is a method provided by the class AsyncOperation.  It raises an event (or more specifically invokes any delegate) on the UI thread of a form or control.  StdOutReceived is the event that will be raised.  DataReceivedEventArgs is a class derived from EventArgs that has a single string containing the text to be displayed (its definition is not shown here for brevity).
The second thing AsyncOperation provides is a method of canceling a process.  Let's take a look at that class in more detail.

Inheriting from AsyncOperation

AsyncOperation is an abstract base class that assists in creating cancelable worker threads that can fire events back on a UI control (or form).  It provides two main methods that are called by a form class: Start() andCancel().
AsyncOperation requires that one method be overridden: DoWork(). This method is called when the Start() method is called.  As the method runs, it is expected to watch for a flag CancelRequested that is set from a call to Cancel().  If the flag is true, the method should acknowledge the cancel and return.
The implementation of DoWork() is as follows:
    void protected override void DoWork()()
    {
        // Start a new process for the cmd
        Process process = new Process();
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.RedirectStandardError = true;
        process.StartInfo.CreateNoWindow = true;
        process.StartInfo.FileName = FileName;
        process.StartInfo.Arguments = Arguments;
        process.StartInfo.WorkingDirectory = WorkingDirectory;
        process.Start();

        
        // Invoke stdOut and stdErr readers - each
        // has its own thread to guarantee that they aren't
        // blocked by, or cause a block to, the actual
        // process running (or the gui).
        new MethodInvoker(ReadStdOut).BeginInvoke(null, null);
        new MethodInvoker(ReadStdErr).BeginInvoke(null, null);

        // Wait for the process to end, or cancel it
        while (! process.HasExited)
        {
            Thread.Sleep(SleepTime); // sleep
            if (CancelRequested)
            {
                // Not a very nice way to end a process,
                // but effective.
                process.Kill();
                AcknowledgeCancel();
            }
        }

    }
The methods DoWork()ReadStdOut(), and ReadStdErr(), the properties FileName and Arguments, and the events StdOutReceived and StdErrReceived are all added to a class ProcessCaller which derives from AsyncOperation.  Both classes can be downloaded as part of the zipfile at the top of the page.

The form

As shown in the picture above, the form is quite simple.  It consists of a rich text box to show the standard output and standard input, a button to run a process (Ok), and a button to cancel the process (Cancel).
The Ok button calls the Start() method on ProcessCaller and the Cancel button calls the Cancel() method.  The events StdOutRecieved and StdErrReceived are handled by the following function:
    private void writeStreamInfo(object sender, DataReceivedEventArgs e)
    {
        this.richTextBox1.AppendText(e.Text + Environment.NewLine);
    }

Improvements

Adding a progress bar to the form is one nice improvement for the user interface.  Of course, you have to know the progress of the program being run.  One option is to have the script tell you explicitly in the standard output with lines such as: "Percent completion = 30".  Your "writeStreamInfo" function would filter those lines and update a progress bar.
Standard Error can be displayed in red or some other color (or in a separate rich text box) to highlight any errors found.  At the end of the process, a dialog could be displayed with a list of all errors.
Providing support for standard input shouldn't be too difficult, but integrating it with the windows form may be tough.  Perhaps a separate single-line text box whose contents are sent to the standard input stream through a method on ProcessCaller.
These are just a few ideas of improvements you can make.

Conclusion

Using the class AsyncOperation reduced the design complexity of this program.  Hopefully, the class ProcessCaller will provide you just as much help in reducing the complexity of running scripts and monitoring the output.

Revision History

  • 2003-Jul-31 : Original Post
  • 2003-Aug-05 : Fixed some spelling / grammatical mistakes (oops)
 

Launching a process and displaying its standard output



Sample Image - LaunchProcess.png

Introduction

I wanted to launch a script from a Windows Form application and display the standard output in a text box as the process was running.  Surely you're not surprised to learn that multithreading is involved.  It turns out you'll have at least four threads running to do this simple task.  To keep things simple and sane, I've reused code from other another source, so I must first give credit to the MSDN article "Give Your .NET-based Application a Fast and Responsive UI with Multiple Threads"  by I.D. Griffiths.  I highly suggest reading this article for more background on multithreading in Windows Forms applications.  Thanks also to Chad Christensen for his suggestions in using a RichTextBox.

Creating a class to call a process

A script or executable can be run using System.Diagnostics.Process.  The string FileName is set to the executable (e.g. perl.exe, Run.bat, ConsoleApplication.exe).  The string Arguments is set to the command-line arguments for that executable (e.g. perlscript.pl, filename1.txt filename2.txt, etc).  The following code will start that executable.
    Process process = new Process();
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;
    process.StartInfo.CreateNoWindow = true;
    process.StartInfo.FileName = FileName;
    process.StartInfo.Arguments = Arguments;
    process.StartInfo.WorkingDirectory = WorkingDirectory;
    process.Start();
Notice that the standard output and standard error have both been redirected.  There are two StreamReaders in the Process class that can be used to read the output: Process.StandardOutput andProcess.StandardError.  Often, the output is not read until after the process has finished, as in the following:
    string output = process.StandardOutput.ReadToEnd();
Reading to the end will not work for this application, since we want to read the data as the process is running.

Multiple threads

The solution is to use multiple threads.  One thread is dedicated to running the process and two more threads are dedicated to reading the standard error and standard output.  This is mentioned in MSDNdocumentation.  Each of these two threads will run a simple function that sits in a loop reading from the stream until the stream is closed.
    void ReadStdOut()
    {
        string str;
        while ((str = process.StandardOutput.ReadLine()) != null)
        {
            // do something with str
        }
    }
After each line is read into str, we would like to notify a windows form to display the text.  Raising an event is probably the best way to accomplish this.  For every new line of text received (on either StandardOutput or StandardError) an event will be raised.  A windows form class can subscribe to these events and update a text box.  Simple, but it won't quite work without some additional work.

Important rule of windows forms

There is an important rule of windows forms and multithreading.  Controls are (almost entirely) not thread safe.  This means that an event raised from any thread other than the UI Thread cannot use methods or properties of a control.  There are a few methods guaranteed to be safe including Control.Invoke and Control.BeginInvoke.  These methods are used to run a function on the UI thread.
Thankfully, we can inherit from the class AsyncOperation (written by I.D. Griffiths from the above mentioned MSDN article) to solve several problems.  First, this class allows us to raise an event on a UI thread of a hosting or target control.  The above function becomes:
    public delegate void DataReceivedHandler(object sender,
        DataReceivedEventArgs e);

    public event DataReceivedHandler StdOutReceived;

    void ReadStdOut()
    {
        string str;
        while ((str = process.StandardOutput.ReadLine()) != null)
        {
            FireAsync(StdOutReceived, this, new DataReceivedEventArgs(str));
        }
    }
FireAsync is a method provided by the class AsyncOperation.  It raises an event (or more specifically invokes any delegate) on the UI thread of a form or control.  StdOutReceived is the event that will be raised.  DataReceivedEventArgs is a class derived from EventArgs that has a single string containing the text to be displayed (its definition is not shown here for brevity).
The second thing AsyncOperation provides is a method of canceling a process.  Let's take a look at that class in more detail.

Inheriting from AsyncOperation

AsyncOperation is an abstract base class that assists in creating cancelable worker threads that can fire events back on a UI control (or form).  It provides two main methods that are called by a form class: Start() andCancel().
AsyncOperation requires that one method be overridden: DoWork(). This method is called when the Start() method is called.  As the method runs, it is expected to watch for a flag CancelRequested that is set from a call to Cancel().  If the flag is true, the method should acknowledge the cancel and return.
The implementation of DoWork() is as follows:
    void protected override void DoWork()()
    {
        // Start a new process for the cmd
        Process process = new Process();
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.RedirectStandardError = true;
        process.StartInfo.CreateNoWindow = true;
        process.StartInfo.FileName = FileName;
        process.StartInfo.Arguments = Arguments;
        process.StartInfo.WorkingDirectory = WorkingDirectory;
        process.Start();

        
        // Invoke stdOut and stdErr readers - each
        // has its own thread to guarantee that they aren't
        // blocked by, or cause a block to, the actual
        // process running (or the gui).
        new MethodInvoker(ReadStdOut).BeginInvoke(null, null);
        new MethodInvoker(ReadStdErr).BeginInvoke(null, null);

        // Wait for the process to end, or cancel it
        while (! process.HasExited)
        {
            Thread.Sleep(SleepTime); // sleep
            if (CancelRequested)
            {
                // Not a very nice way to end a process,
                // but effective.
                process.Kill();
                AcknowledgeCancel();
            }
        }

    }
The methods DoWork()ReadStdOut(), and ReadStdErr(), the properties FileName and Arguments, and the events StdOutReceived and StdErrReceived are all added to a class ProcessCaller which derives from AsyncOperation.  Both classes can be downloaded as part of the zipfile at the top of the page.

The form

As shown in the picture above, the form is quite simple.  It consists of a rich text box to show the standard output and standard input, a button to run a process (Ok), and a button to cancel the process (Cancel).
The Ok button calls the Start() method on ProcessCaller and the Cancel button calls the Cancel() method.  The events StdOutRecieved and StdErrReceived are handled by the following function:
    private void writeStreamInfo(object sender, DataReceivedEventArgs e)
    {
        this.richTextBox1.AppendText(e.Text + Environment.NewLine);
    }

Improvements

Adding a progress bar to the form is one nice improvement for the user interface.  Of course, you have to know the progress of the program being run.  One option is to have the script tell you explicitly in the standard output with lines such as: "Percent completion = 30".  Your "writeStreamInfo" function would filter those lines and update a progress bar.
Standard Error can be displayed in red or some other color (or in a separate rich text box) to highlight any errors found.  At the end of the process, a dialog could be displayed with a list of all errors.
Providing support for standard input shouldn't be too difficult, but integrating it with the windows form may be tough.  Perhaps a separate single-line text box whose contents are sent to the standard input stream through a method on ProcessCaller.
These are just a few ideas of improvements you can make.

Conclusion

Using the class AsyncOperation reduced the design complexity of this program.  Hopefully, the class ProcessCaller will provide you just as much help in reducing the complexity of running scripts and monitoring the output.

Revision History

  • 2003-Jul-31 : Original Post
  • 2003-Aug-05 : Fixed some spelling / grammatical mistakes (oops)
 

access c# insert into 据的语法错误



access c#
"insert into [users](name,password) values('" + name_text.Text + "','" + new_password_text1.Text + "')"
insert into 据的语法错误
在access里面拿去这个sql语句可以添加。但是c#就提示错误。这是为什么呢?





我是不清楚你为什么会报错。
但是以前我因为大小写,和[]的问题,没有成功过。
"INSERT INTO [user]([name],[password]) VALUES('"+name_text.Text+"','"+new_password_text1.Text+"' )"



谢谢你,就是你所说的[]问题。name和password外加[]后解决问题了。

怎么在access2007里执行sql语句



点菜单中的创建-查询设计-关闭-在窗口中间点右键-SQL视图
就可以了

一个简单的C#的ACCESS操作类



这几天一直在忙着用C#+ACCESS写一个winform应用程序,用到从ACCESS数据库查询,并且将数据返回到datagridview中。
由于没有用.net开发的经验,连接ACCESS数据库花费了点精力,最后发现其实要绑定数据到datagridview中,只需把datagridview的datasource设为从数据库读出的datatable就可以了,寻着这个思路,自己写了一个ACCESS的操作类,用起来还蛮方便的,我在这个类中还添加了返回datatable的容器dataset的方法,支持新建或者添加到已有的dataset中,为了避免覆盖原dataset中的同名表,操作返回初始dataset,有一个重载。另外还有一个方法执行无返回的数据库操作,一般可以用于删除。
所有操作直接用SQL语言即可。如果是其他数据库比如Oracle,操作就非常类似,区别主要在构造函数的默认连接字符串上。SQL server的话可能就要有些改动,因为首先using的命名空间不一样,但是操作都是类似的,因为connection,adapter等的父类都是一样的,最后都可以用来跟DataSet或者DataTable沟通。
PS BingdingSource也是个数据库操作过程中非常有用的类,本文中就不多讲了。
假设存在一个ACCESS数据库路径为“c:/db.mdb”,里面有一个表名叫student,并且已经有一个表格控件datagridview1,该类的使用例子如下:
...
using AccessDb;
...
            //初始化,载入数据库路径
            AccessDbClass mydb = new AccessDbClass("c:/db.mdb");

            //返回符合SQL要求的DataTable,并且与控件dataGridView1绑定
            DataTable dt = new DataTable();
            dt = mydb.SelectToDataTable(@"select * from student");
            this.dataGridView1.DataSource = dt;

            //返回DataSet,其中包括一个符合SQL要求和给定名称的DataTable,并且与控件dataGridView1绑定
            DataSet ds = new DataSet();
            ds = mydb.SelectToDataSet(@"select * from student","student");
            this.dataGridView1.DataSource = ds.Tables["student"];
   
            //关闭数据库
            mydb.Close();
因为用法类似,就不再多给例子,使用也确实非常简单。
如果有多个表的话,建议读到一个DataSet中,方便使用和管理。
废话不多说,下面是操作类的代码
在vs2005中编译通过,.net 2.0
using System;
using System.Data;
using System.Data.OleDb;

namespace AccessDb
{
    /// <summary>
    /// AccessDb 的摘要说明,以下信息请完整保留
    /// 请在数据传递完毕后调用Close()方法,关闭数据链接。
    /// </summary>
    public class AccessDbClass
    {

        #region 变量声明处
        public OleDbConnection Conn;
        public string ConnString;//连接字符串
        #endregion


        #region 构造函数与连接关闭数据库
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="Dbpath">ACCESS数据库路径</param>
        public AccessDbClass(string Dbpath)
        {
            ConnString = "Provider=Microsoft.Jet.OleDb.4.0;Data Source=";
            ConnString += Dbpath;
            Conn = new OleDbConnection(ConnString);
            Conn.Open();
        }

        /// <summary>
        /// 打开数据源链接
        /// </summary>
        /// <returns></returns>
        public OleDbConnection DbConn()
        {
            Conn.Open();
            return Conn;
        }

        /// <summary>
        /// 请在数据传递完毕后调用该函数,关闭数据链接。
        /// </summary>
        public void Close()
        {
            Conn.Close();
        }
        #endregion


        #region 数据库基本操作
        /// <summary>
        /// 根据SQL命令返回数据DataTable数据表,
        /// 可直接作为dataGridView的数据源
        /// </summary>
        /// <param name="SQL"></param>
        /// <returns></returns>
        public DataTable SelectToDataTable(string SQL)
        {
            OleDbDataAdapter adapter = new OleDbDataAdapter();
            OleDbCommand command = new OleDbCommand(SQL, Conn);
            adapter.SelectCommand = command;
            DataTable Dt = new DataTable();
            adapter.Fill(Dt);  
            return Dt;
        }

        /// <summary>
        /// 根据SQL命令返回数据DataSet数据集,其中的表可直接作为dataGridView的数据源。
        /// </summary>
        /// <param name="SQL"></param>
        /// <param name="subtableName">在返回的数据集中所添加的表的名称</param>
        /// <returns></returns>
        public DataSet SelectToDataSet(string SQL, string subtableName)
        {
            OleDbDataAdapter adapter = new OleDbDataAdapter();
            OleDbCommand command = new OleDbCommand(SQL, Conn);
            adapter.SelectCommand = command;
            DataSet Ds = new DataSet();
            Ds.Tables.Add(subtableName);
            adapter.Fill(Ds, subtableName);
            return Ds;
        }

        /// <summary>
        /// 在指定的数据集中添加带有指定名称的表,由于存在覆盖已有名称表的危险,返回操作之前的数据集。
        /// </summary>
        /// <param name="SQL"></param>
        /// <param name="subtableName">添加的表名</param>
        /// <param name="DataSetName">被添加的数据集名</param>
        /// <returns></returns>
        public DataSet SelectToDataSet (string SQL, string subtableName, DataSet DataSetName)
        {
            OleDbDataAdapter adapter = new OleDbDataAdapter();
            OleDbCommand command = new OleDbCommand(SQL, Conn);
            adapter.SelectCommand = command;
            DataTable Dt = new DataTable();
            DataSet Ds = new DataSet();
            Ds = DataSetName;
            adapter.Fill(DataSetName, subtableName);
            return Ds;
        }

        /// <summary>
        /// 根据SQL命令返回OleDbDataAdapter,
        /// 使用前请在主程序中添加命名空间System.Data.OleDb
        /// </summary>
        /// <param name="SQL"></param>
        /// <returns></returns>
        public OleDbDataAdapter SelectToOleDbDataAdapter(string SQL)
        {
            OleDbDataAdapter adapter = new OleDbDataAdapter();
            OleDbCommand command = new OleDbCommand(SQL, Conn);
            adapter.SelectCommand = command;
            return adapter;
        }

        /// <summary>
        /// 执行SQL命令,不需要返回数据的修改,删除可以使用本函数
        /// </summary>
        /// <param name="SQL"></param>
        /// <returns></returns>
        public bool ExecuteSQLNonquery(string SQL)
        {
            OleDbCommand cmd = new OleDbCommand(SQL, Conn);
            try
            {
                cmd.ExecuteNonQuery();
                return true;
            }
            catch
            {
                return false;
            }
        }
        #endregion
    }
}