之前我们讲到wpf组件基类以及组件开发,现在我们围绕之前的内容去开发一个组件。
效果图请加群查看,在群共享里面。
做出这个呢 是比较繁琐的。
首先要使用我们的基类
继承基类的模板自动生成如下几个文件:HrvColumnSeries这四个文件 HrvColumnSeries.cs是去设置组件的名称和组件在列表上显示的图片,我们所做的组件不是在vs上使用,而是在我们自己开发的设计器上,所以需要这些。
代码如下:
public class HrvColumnSeries : ComponentBase { public HrvColumnSeries() { Content = new HrvColumnSeriesShape(); } public override string TextName { get { return "HrvColumnSeries"; } } public override string IconName { get { return "HrvColumnSeries.png"; } } }
HrvColumnSeriesEvent.cs 文件 组件在使用时有相应的事件 比如一个button也有click事件 这是我们的事件 一下为例子:
public class HrvColumnSeriesEvent : ComponentEventBase { private string _Click; [Category("基础事件")] [Description("单击事件.")] [EventInfo("Click")] public string Click { get { return _Click; } set { if (_Click == value) return; _Click = value; OnPropertyChanged("Click"); } } public void OnClick(object sender, RoutedEventArgs e) { if (Click != null) { } } }
毫无疑问HrvColumnSeriesProperty.cs 这个就是我们的组件属性了
因为这一章不只是组件 还有数据库数据更新 前台动态更新。
所以属性就比较多如下:
public class HrvColumnSeriesProperty : ComponentPropertyBase { private static string _ComputerName = ".\\sqlexpress"; [Category("数据源")] [Description("计算机名称")] public string ComputerName { get { return _ComputerName; } set { _ComputerName = value; OnPropertyChanged("ComputerName"); } } private string _DataBaseName = "ColumnSeriesDB"; [Category("数据源")] [Description("数据库名称")] public string DataBaseName { get { return _DataBaseName; } set { _DataBaseName = value; OnPropertyChanged("DataBaseName"); } } private string _UID = "sa"; [Category("数据源")] [Description("用户名")] public string UID { get { return _UID; } set { _UID = value; OnPropertyChanged("UID"); } } private string _PWD = "sa"; [Category("数据源")] [Description("密码")] public string PWD { get { return _PWD; } set { _PWD = value; OnPropertyChanged("PWD"); } } private bool _IsWindowLogin = true; [Category("数据源")] [Description("是否为Window身份验证")] public bool IsWindowLogin { get { return _IsWindowLogin; } set { _IsWindowLogin = value; OnPropertyChanged("IsWindowLogin"); } } private string _XTableName = "ColumnSeriesTable"; [Category("数据源")] [Description("X轴表名")] public string XTableName { get { return _XTableName; } set { _XTableName = value; OnPropertyChanged("XTableName"); } } private string _YTableName = "ColumnSeriesData"; [Category("数据源")] [Description("Y轴表名")] public string YTableName { get { return _YTableName; } set { _YTableName = value; OnPropertyChanged("YTableName"); } } private string _XTableID = "ColumnSData"; [Category("数据源")] [Description("X轴表ID")] public string XTableID { get { return _XTableID; } set { _XTableID = value; OnPropertyChanged("XTableID"); } } private string _YTableID = "ID"; [Category("数据源")] [Description("Y轴表ID")] public string YTableID { get { return _YTableID; } set { _YTableID = value; OnPropertyChanged("YTableID"); } } private string _Title = "柱状图"; [Category("基本")] [Description("标题")] public string Title { get { return _Title; } set { _Title = value; OnPropertyChanged("Title"); } } private string _DataColumnName = "MinData;MaxData"; [Category("数据源")] [Description("数据源列名,多数据源名称用分号隔开")] public string DataColumnName { get { return _DataColumnName; } set { _DataColumnName = value; OnPropertyChanged("DataColumnName"); } } private string _XAxisName = "sad ada"; [Category("数据源")] [Description("轴线名称")] public string XAxisName { get { return _XAxisName; } set { _XAxisName = value; OnPropertyChanged("XAxisName"); } } private string _ToolTipName = "asdsa($):"; [Category("数据源")] [Description("轴线提示文本")] public string ToolTipName { get { return _ToolTipName + "{field}"; } set { _ToolTipName = value; OnPropertyChanged("ToolTipName"); } } private bool _ShowValueOnBar=true ; [Category("数据源")] [Description("是否显示数据源标注")] public bool ShowValueOnBar { get { return _ShowValueOnBar; } set { _ShowValueOnBar = value; OnPropertyChanged("ShowValueOnBar"); } } //读取保存的数据 public override void ReadXml(System.Xml.Linq.XElement element) { base.ReadXml(element); ShowValueOnBar = element.ReadBool("ShowValueOnBar", ShowValueOnBar); ToolTipName = element.ReadString("ToolTipName"); XAxisName = element.ReadString("XAxisName"); DataColumnName = element.ReadString("DataColumnName"); Title = element.ReadString("Title"); YTableID = element.ReadString("YTableID"); XTableID = element.ReadString("XTableID"); YTableName = element.ReadString("YTableName"); XTableName = element.ReadString("XTableName"); IsWindowLogin = element.ReadBool("IsWindowLogin", IsWindowLogin); PWD = element.ReadString("PWD"); UID = element.ReadString("UID"); DataBaseName = element.ReadString("DataBaseName"); ComputerName = element.ReadString("ComputerName"); } //保存属性 public override void WriteXml(System.Xml.XmlWriter writer) { base.WriteXml(writer); writer.WriteAttributeString("ShowValueOnBar", ShowValueOnBar.ToString()); writer.WriteAttributeString("ToolTipName", ToolTipName); writer.WriteAttributeString("XAxisName", XAxisName); writer.WriteAttributeString("DataColumnName", DataColumnName); writer.WriteAttributeString("Title", Title); writer.WriteAttributeString("YTableID", YTableID); writer.WriteAttributeString("XTableID", XTableID); writer.WriteAttributeString("YTableName", YTableName); writer.WriteAttributeString("XTableName", XTableName); writer.WriteAttributeString("IsWindowLogin", IsWindowLogin.ToString()); writer.WriteAttributeString("PWD", PWD); writer.WriteAttributeString("UID", UID); writer.WriteAttributeString("DataBaseName", DataBaseName); writer.WriteAttributeString("ComputerName", ComputerName); } }
在这里我们使用的是固定的数据格式 包括数据库的表也是固定的。
至于这些属性呢 数据库名称什么的我们可以自己去设置 唯有格式是固定的,下面的保存和读取是当组件放在设计器上的时候有编辑完的东西需要保存,当保存了是设计器上的东西时 当然也需要保存组件的属性了,这个保存的方法在基类。
至于HrvColumnSeriesShape.cs 我们用作将组件的属性以及事件去绑定起来(双向绑定) 可以保证属性的动态变化
public class HrvColumnSeriesShape : HrvContent { public HrvColumnSeriesProperty _Property; public HrvColumnSeriesEvent _Event; public HrvColumnSeriesShape() { this.Content = new ColumnSeries(); BindingOperations.SetBinding(this.Content as ColumnSeries, ColumnSeries.ComputerNameProperty, new Binding("ComputerName") { Source = this.Property, Mode = BindingMode.TwoWay }); BindingOperations.SetBinding(this.Content as ColumnSeries, ColumnSeries.DataBaseNameProperty, new Binding("DataBaseName") { Source = this.Property, Mode = BindingMode.TwoWay }); BindingOperations.SetBinding(this.Content as ColumnSeries, ColumnSeries.UIDProperty, new Binding("UID") { Source = this.Property, Mode = BindingMode.TwoWay }); BindingOperations.SetBinding(this.Content as ColumnSeries, ColumnSeries.PWDProperty, new Binding("PWD") { Source = this.Property, Mode = BindingMode.TwoWay }); BindingOperations.SetBinding(this.Content as ColumnSeries, ColumnSeries.IsWindowLoginProperty, new Binding("IsWindowLogin") { Source = this.Property, Mode = BindingMode.TwoWay }); BindingOperations.SetBinding(this.Content as ColumnSeries, ColumnSeries.XTableNameProperty, new Binding("XTableName") { Source = this.Property, Mode = BindingMode.TwoWay }); BindingOperations.SetBinding(this.Content as ColumnSeries, ColumnSeries.YTableNameProperty, new Binding("YTableName") { Source = this.Property, Mode = BindingMode.TwoWay }); BindingOperations.SetBinding(this.Content as ColumnSeries, ColumnSeries.TitleProperty, new Binding("Title") { Source = this.Property, Mode = BindingMode.TwoWay }); BindingOperations.SetBinding(this.Content as ColumnSeries, ColumnSeries.DataColumnNameProperty, new Binding("DataColumnName") { Source = this.Property, Mode = BindingMode.TwoWay }); BindingOperations.SetBinding(this.Content as ColumnSeries, ColumnSeries.XAxisNameProperty, new Binding("XAxisName") { Source = this.Property, Mode = BindingMode.TwoWay }); BindingOperations.SetBinding(this.Content as ColumnSeries, ColumnSeries.ToolTipNameProperty, new Binding("ToolTipName") { Source = this.Property, Mode = BindingMode.TwoWay }); BindingOperations.SetBinding(this.Content as ColumnSeries, ColumnSeries.ShowValueOnBarProperty, new Binding("ShowValueOnBar") { Source = this.Property, Mode = BindingMode.TwoWay }); BindingOperations.SetBinding(this.Content as ColumnSeries, ColumnSeries.XTableIDProperty, new Binding("XTableID") { Source = this.Property, Mode = BindingMode.TwoWay }); BindingOperations.SetBinding(this.Content as ColumnSeries, ColumnSeries.YTableIDProperty, new Binding("YTableID") { Source = this.Property, Mode = BindingMode.TwoWay }); } public override ComponentPropertyBase Property { get { if (_Property == null) { _Property = new HrvColumnSeriesProperty(); } return _Property; } } public override ComponentEventBase Event { get { if (_Event == null) { _Event = new HrvColumnSeriesEvent(); } return _Event; } }
如此我们的组件基本的构成就讲完了,接下来就是数据的读取以及前端的动态更新了!
ColumnSeries.xaml.cs属性如下:
#region 属性 public static DependencyProperty ComputerNameProperty = DependencyProperty.Register("ComputerName", typeof(string), typeof(ColumnSeries)); public string ComputerName { get { return (string)GetValue(ComputerNameProperty); } set { SetValue(ComputerNameProperty, value); } } public static DependencyProperty DataBaseNameProperty = DependencyProperty.Register("DataBaseName", typeof(string), typeof(ColumnSeries)); public string DataBaseName { get { return (string)GetValue(DataBaseNameProperty); } set { SetValue(DataBaseNameProperty, value); } } public static DependencyProperty UIDProperty = DependencyProperty.Register("UID", typeof(string), typeof(ColumnSeries)); public string UID { get { return (string)GetValue(UIDProperty); } set { SetValue(UIDProperty, value); } } public static DependencyProperty PWDProperty = DependencyProperty.Register("PWD", typeof(string), typeof(ColumnSeries)); public string PWD { get { return (string)GetValue(PWDProperty); } set { SetValue(PWDProperty, value); } } public static DependencyProperty IsWindowLoginProperty = DependencyProperty.Register("IsWindowLogin", typeof(bool), typeof(ColumnSeries)); public bool IsWindowLogin { get { return Convert.ToBoolean(GetValue(IsWindowLoginProperty)); } set { SetValue(IsWindowLoginProperty, value); } } public static DependencyProperty XTableNameProperty = DependencyProperty.Register("XTableName", typeof(string), typeof(ColumnSeries)); public string XTableName { get { return (string)GetValue(XTableNameProperty); } set { SetValue(XTableNameProperty, value); } } public static DependencyProperty YTableNameProperty = DependencyProperty.Register("YTableName", typeof(string), typeof(ColumnSeries)); public string YTableName { get { return (string)GetValue(YTableNameProperty); } set { SetValue(YTableNameProperty, value); } } public static DependencyProperty XTableIDProperty = DependencyProperty.Register("XTableID", typeof(string), typeof(ColumnSeries)); public string XTableID { get { return (string)GetValue(XTableIDProperty); } set { SetValue(XTableIDProperty, value); } } public static DependencyProperty YTableIDProperty = DependencyProperty.Register("YTableID", typeof(string), typeof(ColumnSeries)); public string YTableID { get { return (string)GetValue(YTableIDProperty); } set { SetValue(YTableIDProperty, value); } } public static DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(ColumnSeries)); public string Title { get { return (string)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } public static DependencyProperty DataColumnNameProperty = DependencyProperty.Register("DataColumnName", typeof(string), typeof(ColumnSeries)); public string DataColumnName { get { return (string)GetValue(DataColumnNameProperty); } set { SetValue(DataColumnNameProperty, value); } } public static DependencyProperty XAxisNameProperty = DependencyProperty.Register("XAxisName", typeof(string), typeof(ColumnSeries)); public string XAxisName { get { return (string)GetValue(XAxisNameProperty); } set { SetValue(XAxisNameProperty, value); } } public static DependencyProperty ToolTipNameProperty = DependencyProperty.Register("ToolTipName", typeof(string), typeof(ColumnSeries)); public string ToolTipName { get { return (string)GetValue(ToolTipNameProperty); } set { SetValue(ToolTipNameProperty, value); } } public static DependencyProperty ShowValueOnBarProperty = DependencyProperty.Register("ShowValueOnBar", typeof(bool), typeof(ColumnSeries)); public bool ShowValueOnBar { get { return Convert.ToBoolean(GetValue(ShowValueOnBarProperty)); } set { SetValue(ShowValueOnBarProperty, value); } } private DataSet _Data; public DataSet Data { get { return _Data; } set { _Data = value; } } #endregion
为什么定义这种呢? 这是为了将组件的属性和数据读取这一块绑定 为了保证在绑定之后属性的动态变化,所以我们使用了依赖项属性。
关于监听数据库值得改变去动态显示数据(SqlDependency)这部分内容在
这一章节会有详细的讲解,以下内容 看的懂看一下 觉得繁琐的 就不看了。
数据的读取:
private string con; private string[] dataColumn; private string sql; #region 数据库连接 public void GetDataSet() { SqlConnection connection = new SqlConnection(con); Data = new DataSet(); SqlCommand command = new SqlCommand(sql, connection); command.CommandType = CommandType.Text; connection.Open(); SqlDependency dependency = new SqlDependency(command); dependency.OnChange += new OnChangeEventHandler(dependency_OnChange); DataTable dt = new DataTable(); SqlDataReader sda = command.ExecuteReader(); foreach (string data in dataColumn) { DataColumn dc = new DataColumn(data); dt.Columns.Add(dc); } while (sda.Read()) { DataRow row = dt.NewRow(); foreach (string data in dataColumn) { row[data] = sda[data].ToString(); } dt.Rows.Add(row); } Data.Tables.Add(dt); sda.Close(); //} //catch (Exception ex) //{ //} } private void dependency_OnChange(object sender, SqlNotificationEventArgs e) { DrawChart(); } #endregion string CName; string DName; string ID; string PassWord; bool windowLogin; string XTName; string YTName; string DCName; string XAName; string XTID; string YTID; protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { base.OnPropertyChanged(e); if (CName != null && DName != null && ID != null && PassWord != null && XTName != null && YTName != null && DCName != null && XAName != null && XTID != null && YTID != null) if (CName != ComputerName || DName != DataBaseName || ID != UID || PassWord != PWD || windowLogin != IsWindowLogin || XTName != XTableName || YTName != YTableName || DCName != DataColumnName || XAName != XAxisName || XTID != XTableID || YTID != YTableID) DrawChart(); CName = ComputerName; DName = DataBaseName; ID = UID; PassWord = PWD; windowLogin = IsWindowLogin; XTName = XTableName; YTName = YTableName; DCName = DataColumnName; XAName = XAxisName; XTID = XTableID; YTID = YTableID; } #region 显示数据 private void DrawChart() { this.Dispatcher.Invoke(new System.Action(() => { con = @"server=" + ComputerName + @";database=" + DataBaseName + ";uid=" + UID + ";pwd=" + PWD + ";Integrated Security=" + IsWindowLogin; dataColumn = (DataColumnName + ";Name").Split(';'); sql = "SELECT "; foreach (string data in dataColumn) { sql += data + ","; } sql = sql.Remove(sql.Length - 1); sql += " FROM [dbo].[" + XTableName + "] INNER JOIN [dbo].[" + YTableName + "] ON " + YTableName + "." + YTableID + "=" + XTableName + "." + XTableID; try { SqlDependency.Start(con); GetDataSet(); } catch(Exception ex) { MessageBox.Show(ex.Message.ToString(),"数据连接错误!"); } chart2.Reset(); Binding titleBind = new Binding { Source = this, Path = new PropertyPath("Title") }; BindingOperations.SetBinding(this.chart2, BarChart.TitleProperty, titleBind); string[] column = new string[dataColumn.Length - 1]; for (int i = 0; i < dataColumn.Length - 1; i++) { column[i] = dataColumn[i]; } if (column == null) return; foreach (string data in column) { chart2.ValueField.Add(data); } Binding ToolTipNameBind = new Binding { Source = this, Path = new PropertyPath("ToolTipName") }; BindingOperations.SetBinding(this.chart2, BarChart.ToolTipTextProperty, ToolTipNameBind); chart2.XAxisText = XAxisName; chart2.XAxisField = "Name"; Binding showBarBind = new Binding { Source = this, Path = new PropertyPath("ShowValueOnBar") }; BindingOperations.SetBinding(this.chart2, BarChart.ShowValueOnBarsProperty, showBarBind); if (Data == null) return; Binding DataSourceBind = new Binding { Source = this, Path = new PropertyPath("Data") }; BindingOperations.SetBinding(this.chart2, BarChart.DataSourceProperty, DataSourceBind); chart2.Generate(); })); } #endregion private void UserControl_Loaded(object sender, RoutedEventArgs e) { DrawChart(); } private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e) { chart2.Width = 450; chart2.Height = 300; }
OnPropertyChanged解释下这个 这个是在属性更改的时候发生,因为数据库的连接字符串是无法做动态更新的 比如更改完数据库名称之后马上要自动去连接那个数据库之前的方法就无法实现了,所以我们使用了这个事件 当数据库名称、表名、列明等发生改变的时候去重新获取数据。 目前就讲这些,至于柱状图下章继续,柱状图更加繁琐。 需要组件基类模板的,想要柱状图源码的请加群:
WPF、AE技术交流群:94234450
点击加入QQ群:
不管你遇到了什么问题,我们都不会让你独自去面对!