之前我们讲到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)这部分内容在

WPF非轮询方式更新数据库变化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群:

不管你遇到了什么问题,我们都不会让你独自去面对!

												

WPF柱状图(支持数据库动态更新)的更多相关文章

  1. WPF柱状图(支持数据库动态更新)之组件的数据动态化

    WPF柱状图(支持数据库动态更新) 在这片文章中我们介绍了如何将柱状图包装成一个组件,将这个组件的属性对外开放和组件的外部属性根内部属性绑定以及非轮询动态更新数据的方式. 非轮询更新数据感觉介绍的不够 ...

  2. WPF非轮询方式更新数据库变化SqlDependency(数据库修改前台自动更新)

    上一章节我们讲到wpf的柱状图组件,它包含了非轮询方式更新数据库变化SqlDependency的内容,但是没有详细解释,现在给大家一个比较简单的例子来说明这部分内容. 上一章节: WPF柱状图(支持数 ...

  3. WPF中动态更新TextBlock文字中的超链接,文本

    1.------------------------------------------------------------------------- 修改超链接的文本文字: <TextBloc ...

  4. highcharts图表组件入门教程:如何监听柱状图柱子点击事件动态更新当前数据点数值和所对应X轴刻度

    highcharts图表组件入门教程:如何监听柱状图柱子点击事件动态更新当前数据点数值和所对应X轴刻度 作者:highcharts | 时间:2014-6-11 14:07:05 | [小  大] | ...

  5. .NET6运行时动态更新限流阈值

    昨天博客园撑不住流量又崩溃了,很巧正在编写这篇文章,于是产生一个假想:如果博客园用上我这个限流组件会怎么样呢? 用户会收到几个429错误,并且多刷新几次就看到了内容,不会出现完全不可用. 还可以降低查 ...

  6. JSPatch – 动态更新iOS APP

    原文:http://blog.cnbang.net/works/2767/ JSPatch是最近业余做的项目,只需在项目中引入极小的引擎,就可以使用JavaScript调用任何Objective-C的 ...

  7. elasticsearch同义词及动态更新

    第一种:参考地址:http://dev.paperlesspost.com/setting-up-elasticsearch-synonyms/271.Add a synonyms file.2.Cr ...

  8. iOS 利用 Framework 进行动态更新

    http://nixwang.com/2015/11/09/ios-dynamic-update/ 前言 目前 iOS 上的动态更新方案主要有以下 4 种: HTML 5 lua(wax)hotpat ...

  9. mybatis(二)接口编程 、动态sql 、批量删除 、动态更新、连表查询

    原理等不在赘述,这里主要通过代码展现. 在mybatis(一)基础上,新建一个dao包,并在里面编写接口,然后再在xml文件中引入接口路径,其他不变,在运用阶段将比原始方法更节约时间,因为不用再去手动 ...

随机推荐

  1. SpringBoot入门 一 构建简单工程

    环境准备:jdk1.7(推荐)以上,tomcat8(推荐)以上,或者使用插件自带.mevan插件3.2以上,eclipse编辑工具 pom文件基本配置如下 <project xmlns=&quo ...

  2. 【HDOJ】1026 Ignatius and the Princess I

    这道题搞了很久啊.搜索非常好的一道题.昨天想了2小时,以为是深搜,但后来发现深搜怎么也没法输出正确路径.今天拿宽搜试了一下,问题就是普通的队列宽搜没法得到当前时间最小值.看了一下讨论区,发现优先级队列 ...

  3. URAL1009

    链接 第一道URAL题 简单递推 #include <iostream> #include<cstdio> #include<cstring> #include&l ...

  4. 对XX证券报关于物联网操作系统的几个问题的答复

    XX证券报提问了几个关于物联网和物联网操作系统的问题,个人表达了一些粗陋的观点,在这里发表出来,与行业朋友交流和探讨. 物联网行业最需要解决的问题是什么? 虽然物联网这个行业被炒得比较热,但是截至目前 ...

  5. CSS学习笔记——定位position属性的学习

    今天学习之前剩下的一个问题:CSS的position属性.首先归纳出和position相关的问题: position作为一个属性,它一共有哪几个属性值? position常用的属性值有哪几个?分别有什 ...

  6. MongoDB 权限 验证

    在MongoDB中,服务启动默认是没有权限验证的,就安全性方面来说,这肯定是不行的,所以需要加上权限验证. 既然是要进行权限验证,那肯定是得有用户的吧,所以权限验证的第一步就是给MongoDB库添加用 ...

  7. WFS

    Web 要素服务(WFS) 1定义 支持对地理要素的插入,更新,删除,检索和发现服务.该服务根据HTTP客户请求返回GML(Geography Markup Language.地理标识语言)数据. W ...

  8. date命令--修改linux系统时间

    在linux环境中,不管是编程还是其他维护,时间是必不可少的,也经常会用到时间的运算,熟练运用date命令来表示自己想要表示的时间,肯定可以给自己的工作带来诸多方便. 1.命令格式: date [参数 ...

  9. 分别应用include指令和include动作标识在一个jsp页面中包含一个文件。

    分别应用include指令和include动作标识在一个jsp页面中包含一个文件. hello.jsp <%@ page language="java" import=&qu ...

  10. HNU13377:Book Club 二分图

    题意:有n个人,m种需求,给出m行,每行a,b代表a想要的书在b那里,问能不能通过交换的方法来满足每个人的需求 思路:要符合题意的话一定是二分图.网上还一种dfs #include<cstdio ...