contextmenustrip(contextmenustrip与ContextMenu的差别)
在这个信息爆炸的时代,了解contextmenustrip和contextmenustrip与ContextMenu的差别的重要性不言而喻。本文将为您带来全面的解读,助您在这个领域中游刃有余。
c#winform contentmenustrip
调用方式:.net2.0中SqlDependency
背景需求:对于数据中表A数据字段的变更,需要引发相应业务逻辑,插入或更新相关表或字段。在以往的方式我们多会在数据库端下文章,建立相应触发器,来完成业务逻辑操作。不过这种方式仅适用于单纯对于数据操作的需求,可是当我们要完成更复杂的业务需求是却不太容易了(虽然sql05已经支持托管代码的使用了)。可能你会想到我们可以轮询数据库相关表或视图,来发现数据的变化,可是这对于性能和即时性却是个不容易取舍的问题。不过在SqlServer2005中有了新的方案,那就是查询通知。
查询通知是在MicrosoftSQLServer2005中以及ADO.NET2.0的System.Data.SqlClient命名空间中引入的。查询通知建立在ServiceBroker基础结构的基础上,使应用程序可以在数据更改时收到通知。如果应用程序提供数据库中信息的缓存(例如Web应用程序),需要在源数据更改时接收通知,此功能特别有用。
通过三种方式可以使用ADO.NET实现查询通知:
低级实现由SqlNotificationRequest类提供,该类公开服务器端功能,使您可以对通知请求执行命令。
高级实现由SqlDependency类提供,该类提供源应用程序与SQLServer之间通知功能的高级抽象,使您可以使用相关性来检测服务器中的更改。大多数情况下,这是托管客户端应用程序通过适用于SQLServer的.NETFramework数据提供程序利用SQLServer通知功能的最简单、最有效的方法。
此外,使用ASP.NET2.0(或更高版本)构建的Web应用程序可以使用SqlCacheDependency帮助器类。
如果应用程序需要通过刷新显示或缓存来响应基础数据中的更改,查询通知非常有用。如果执行相同命令生成的结果集与最初检索到的结果集不同,则MicrosoftSQLServer可允许.NETFramework应用程序向SQLServer发送命令和请求通知。服务器上生成的通知通过队列发送,供以后处理。
您可以为SELECT和EXECUTE语句设置通知。使用EXECUTE语句时,SQLServer会为执行的命令而不是EXECUTE语句本身注册通知。该命令必须满足SELECT语句的要求和限制。当注册通知的命令包含多个语句时,数据库引擎会为批处理中的每个语句创建一个通知。
使用查询通知的应用程序有一组通用的要求。必须正确配置数据源才能支持SQL查询通知,并且用户必须具有正确的客户端和服务器端权限。
要使用查询通知,必须符合下列条件:
1.使用SQLServer2005或SQLServer2008。
2.对数据库启用查询通知。
3.确保用于连接数据库的用户ID具有必要的权限。
4.使用SqlCommand对象执行有效的SELECT语句,包含关联的通知对象—SqlDependency或SqlNotificationRequest。
5.提供所监视的数据更改时用于处理通知的代码。
下面就以一个例子来说明使用SqlDependency的整个流程
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using System.Configuration;
using System.Windows.Forms;
namespace CaptureWeb
{
public class SQLServiceBroker
{
private string connectionStr= ConfigurationManager.ConnectionStrings["ConnectionString"].ToString();
private string sqlStr="";
private SqlConnection connection= null;
public delegate void UIDelegate();
private UIDelegate uidel= null;
public Form form= null;
///<summary>
///
///</summary>
///<param name="TableName"></param>
///<param name="ColumnNames"></param>
public SQLServiceBroker(string TableName, List<string> ColumnNames)
{
string columns="";
foreach(string str in ColumnNames)
{
if(columns!="")
columns= columns+",";
columns= columns+"["+ str+"]";
}
this.sqlStr= string.Format("select{0} From [dbo].[{1}]", columns, TableName);
}
///<summary>
///
///</summary>
///<param name="constr"></param>
///<param name="TableName"></param>
///<param name="ColumnNames"></param>
public SQLServiceBroker(string constr, string TableName, List<string> ColumnNames)
: this(TableName, ColumnNames)
{
this.connectionStr= ConfigurationManager.ConnectionStrings[constr].ToString();
}
///<summary>
///
///</summary>
~SQLServiceBroker()
{
StopDependency();
connection.Dispose();
}
///<summary>
///
///</summary>
///<returns></returns>
public bool EnoughPermission()
{
SqlClientPermission perm= new SqlClientPermission(System.Security.Permissions.PermissionState.Unrestricted);
try
{
perm.Demand();
return true;
}
catch(System.Exception)
{
return false;
}
}
///<summary>
///
///</summary>
///<param name="uidelegate"></param>
public void InitDependency(UIDelegate uidelegate)
{
SqlDependency.Stop(connectionStr);
SqlDependency.Start(connectionStr);
if(connection== null)
connection= new SqlConnection(connectionStr);
if(!EnoughPermission())
throw new Exception("没有权限(SqlClientPermission)!");
if(uidelegate== null)
throw new Exception("回调方法未指定(UIDelegate)!");
if(connection== null)
throw new Exception("未初始化(InitDependency)!");
this.uidel= uidelegate;
}
///<summary>
///传入窗体对象,以防止委托有需要访问UI层控件是引发的“从不是创建控件的线程访问它”
///</summary>
///<param name="form1"></param>
///<param name="uidelegate"></param>
public void InitDependency(Form form1, UIDelegate uidelegate)
{
InitDependency(uidelegate);
this.form= form1;
}
///<summary>
///
///</summary>
public void StartDependency()
{
//这里很奇怪,每次都需要新的command对象
using(SqlCommand command= new SqlCommand(sqlStr, connection))
{
command.Notification= null;
SqlDependency dependency= new SqlDependency(command);
dependency.OnChange+= new OnChangeEventHandler(dependency_OnChange);
if(connection.State!= ConnectionState.Open)
connection.Open();
command.ExecuteNonQuery();
command.Dispose();
}
}
///<summary>
///
///</summary>
public void StopDependency()
{
SqlDependency.Stop(connectionStr);
if(connection!= null)
connection.Close();
}
///<summary>
///
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
//注销监测事件
SqlDependency dependency=(SqlDependency)sender;
dependency.OnChange-= dependency_OnChange;
//放在移除事件之后又很大必要,防止ui层调用更新相同表时,进入循环出发调用
//uidel.Invoke();
//uidel();
//使用from.Invoke调用防止访问界面控件引发“从不是创建控件的线程访问它”
if(form!= null)
form.Invoke(uidel);
else
uidel();
//再次启动监听
StartDependency();
}
}
}
调用方式:
SQLServiceBroker broker;
private void button1_Click(object sender, EventArgs e)
{
//需要监测的列
List<string> columns= new List<string>();
columns.Add("test1");
columns.Add("test2");
string table="test";
broker= new SQLServiceBroker(table, columns);
//实例化毁掉函数
SQLServiceBroker.UIDelegate uidel= new SQLServiceBroker.UIDelegate(writeCon);
//初始化,及传入回调函数
broker.InitDependency(uidel);
//初始化,传入窗体对象对于需要委托中访问ui控件的情况
//broker.InitDependency(this, uidel);
//启动监听
broker.StartDependency();
MessageBox.Show("启动");
}
private void writeCon()
{
MessageBox.Show("changed");
}
代码比较简单,都有说明,这里有必要注意几点问题:
1.首先需要在SQLServer2005上执行ALTERDATABASE<DatabaseName>SETENABLE_BROKER;语句让相应的数据库启用监听服务,以便支持SqlDependency特性。
2.对于SqlCommand的cmdText有特殊要求,其中不能用*,不能用top,不能用函数,包括聚合函数,不能用子查询,包括where后的子查询,不能用外连接,自连接,不能用临时表,不能用变量,不能用视图,不能垮库,表名之前必须加类似dbo数据库所有者这样的前缀。
3.其中在使用当中发现SqlConnection对象应该是一直存在的,因此在此示例中升级为属性,如果将它生命在StartDependency方法体中,出现只能调用一次的情况,因为对于SqlDependency需要connection对象的存在。
4.在使用委托传入调用方法是,如果方法有访问界面UI控件的情况,需要传入窗体对象,以form.Invoke(uidel);的方式调用,否则会引发“从不是创建控件的线程访问它”异常。
5.对于回调函数中需要更新正在监听的表时防止循环调用造成死循环,请在调用委托之前先移除onchange事件dependency.OnChange-=dependency_OnChange;
实例..代码..已经上传..
SQLServiceBroker broker;
private void button1_Click(object sender, EventArgs e)
{
//需要监测的列
List&lt;string&gt; columns= new List&lt;string&gt;();
columns.Add("test1");
columns.Add("test2");
string table="test";
broker= new SQLServiceBroker(table, columns);
//实例化毁掉函数
SQLServiceBroker.UIDelegate uidel= new SQLServiceBroker.UIDelegate(writeCon);
//初始化,及传入回调函数
broker.InitDependency(uidel);
//初始化,传入窗体对象对于需要委托中访问ui控件的情况
//broker.InitDependency(this, uidel);
//启动监听
broker.StartDependency();
//在这里重新查询TEST然后绑定数据...
}
private void writeCon()
{
MessageBox.Show("changed");
}
其实只需要改动一点点
如果按照你评论说的那么简单
其实就是下面这3句话解决
public Form2()
{
InitializeComponent();
this.contextMenuStrip1.Opening+=new CancelEventHandler(contextMenuStrip1_Opening);
}
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
{
//在这里查询数据库
this.contextMenuStrip1.Items.Add("菜单项目1");
this.contextMenuStrip1.Items.Add("菜单项目2");
this.contextMenuStrip1.Items.Add("菜单项目3");
this.contextMenuStrip1.Items.Add("菜单项目4");
this.contextMenuStrip1.Items.Add("菜单项目5");
}
C#中的ConTextMenuStrip怎么用
ContextMenuStrip控件提供了与某个控件关联的快捷菜单。也就是说通过这个控件可以方便的实现在别的控件上弹出右键快捷菜单。
我给你个例子:
1、先添加一个ContextMenuStrip控件到Form上
2、设置目标控件(如窗体、文本框等)的ContextMenuStrip属性,指向你刚才添加的ContextMenuStrip控件。这样就实现了两者的关联。
3、动态将一些菜单项添加到 ContextMenuStrip控件中,如:
//上下文菜单项
ContextMenuStrip1.Items.Add(msEditNew);
ContextMenuStrip1.Items.Add(msEditBar1);
ContextMenuStrip1.Items.Add(msEditCut);
ContextMenuStrip1.Items.Add(msEditPaste);
ContextMenuStrip1.Items.Add(msEditDelete);
ContextMenuStrip1.Items.Add(msEditBar2);
这样就OK了,你在目标控件上按右键时将弹出快捷菜单。
contextmenustrip与ContextMenu的差别
ContextMenu是VS2005里的,08升级成ContextMenuStrip。升级后的元件功能更强。
ContextMenuStrip替换 ContextMenu。可以将 ContextMenuStrip与任何控件关联,单击鼠标右键会自动显示快捷菜单。您可以通过使用 Show方法以编程方式显示 ContextMenuStrip。ContextMenuStrip支持可取消的 Opening和 Closing事件以处理动态填充和多次单击方案。ContextMenuStrip支持图像、菜单项复选状态、文本、访问键、快捷键和级联菜单。
虽然 ContextMenuStrip对以前版本的 ContextMenu控件的功能进行了替换和添加,但是考虑到向后兼容性和将来的使用(如果的确需要),仍然保留了 ContextMenu。
好了,文章到此结束,希望可以帮助到大家。