我有一个实时图表,我正在尝试对Button_Click
事件执行值的刷新,但图表没有刷新。
我有两个TextBoxes
,用户可以在其中选择他们想要查看的开始和结束日期,并使用butn_ExecuteQuery_Click
来显示数据。
public HBDBreakdown()
{
InitializeComponent();
ChartValues();
}
private void ChartValues()
{
try
{
// Defines the variable for differnt lines.
List<double> SmallCommercialIndustValues = new List<double>();
List<double> ResidentialValues = new List<double>();
List<string> AnalystName = new List<string>();
SqlConnection connection = new SqlConnection("Data Source=WINDOWS-B1AT5HC\MSSQLSERVER2;Initial Catalog=CustomerRelations;user id=sa; password=Westside2$; Integrated Security=False;");
string selectQuery = ("SELECT Users.TX_EMPLOYEE, SUM(CASE WHEN d .REV_CLS <> 2 THEN 1 ELSE 0 END) AS Residential, SUM(CASE WHEN d .REV_CLS = 2 THEN 1 ELSE 0 END) AS SmallCommercialIndust FROM hb_Disputes AS d INNER JOIN Users ON d.ASSGNTO = Users.KY_USER_ID WHERE(d.OPENED >=@OPENED) AND(d.OPENED < @CLOSED) GROUP BY Users.TX_EMPLOYEE; ");
connection.Open();
SqlCommand command = new SqlCommand(selectQuery, connection);
command.Parameters.Add("@OPENED", SqlDbType.DateTime).Value = dtepicker_Open.Text;
command.Parameters.Add("@CLOSED", SqlDbType.DateTime).Value = dtepicker_DateResolved.Text;
SqlDataReader sqlReader = command.ExecuteReader();
while (sqlReader.Read())
{
// Check for DBNull and then assign the variable
if (sqlReader["SmallCommercialIndust"] != DBNull.Value)
SmallCommercialIndustValues.Add(Convert.ToInt32(sqlReader["SmallCommercialIndust"]));
// Check for DBNull and then assign the variable
if (sqlReader["Residential"] != DBNull.Value)
ResidentialValues.Add(Convert.ToInt32(sqlReader["Residential"]));
// Check for DBNull and then assign the variable
AnalystName.Add(Convert.ToString(sqlReader["TX_EMPLOYEE"]));
}
SeriesCollection = new SeriesCollection
{
new StackedColumnSeries
{
Title = "Residential",
Values = new ChartValues<double>(ResidentialValues),
StackMode = StackMode.Values, // this is not necessary, values is the default stack mode
DataLabels = true
},
new StackedColumnSeries
{
Title = "Small Commercial Indust",
Values = new ChartValues<double>(SmallCommercialIndustValues),
StackMode = StackMode.Values,
DataLabels = true
}
};
Labels = AnalystName.ToArray();
//Formatter = value => value + " Disputes";
DataContext = this;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public SeriesCollection SeriesCollection { get; set; }
public string[] Labels { get; set; }
public Func<double, string> Formatter { get; set; }
private void butn_ExecuteQuery_Click(object sender, RoutedEventArgs e)
{
// Refresh Chart
ChartValues();
}
在调用ChartValues()
或实现INotifyPropertyChanged
并从源属性的setter引发PropertyChanged
事件之前设置DataContext = null;
。
最好不要只为更新某些属性的数据绑定而重置DataContext
。这将导致性能非常差,因为整个视图将被迫再次渲染。DataContext
也是从元素树向下继承的
更好地编写更干净的代码,更优雅地处理动态数据,并符合框架的要求(请参阅数据绑定概述(。
在控件内部(或通常在DependencyObject
上(,您应该始终将数据绑定中涉及的所有属性实现为DependencyProperty
它们将自动刷新目标,并根据Binding.Mode
以及特定Binding
的来源
由于您正在重新分配SeriesCollection
和Labels
,因此这两个属性都应该是DependencyProperty
。
在您的情况下,您可以不实现依赖属性,因为您只是在更新集合。因此,只需避免在每次刷新时重新分配新集合,而是在实现INotifyCollectionChanged
的集合上使用IList.Clear
和IList.Add
。
SeriesCollection
已经实现了INotifyCollectionChanged
,所以您只需要将Labels
属性的类型从string[]
更改为ObservableCollection<string>
。通过这种方式,IList.Clear
和IList.Add
操作将由绑定目标(图表控件(自动反映:
public SeriesCollection SeriesCollection { get; set; }
public ObservableCollection<string> Labels { get; set; }
public HBDBreakdown()
{
InitializeComponent();
// Set the `DataContext` once in the constructor
this.DataContext = this;
// Initialize the collection to prepare them for dynamic clear/add
this.SeriesCollection = new SeriesCollection();
this.Labels = new ObservableCollection<string>();
}
private void ChartValues()
{
try
{
...
this.SeriesCollection.Clear();
this.SeriesCollection.Add(
new StackedColumnSeries
{
Title = "Residential",
Values = new ChartValues<double>(ResidentialValues),
StackMode = StackMode.Values, // this is not necessary, values is the default stack mode
DataLabels = true
});
this.SeriesCollection.Add(
new StackedColumnSeries
{
Title = "Small Commercial Indust",
Values = new ChartValues<double>(SmallCommercialIndustValues),
StackMode = StackMode.Values,
DataLabels = true
});
this.Labels.Clear();
AnalystName.ForEach(this.Labels.Add);
}
// Code smell: never catch 'Exception'.
// Only catch explicitly those exception you can handle.
// A user can't handle exceptions, so in a real business application you wouldn't show the exception message to the user.
catch (Exception ex)
{
// Bad practice
MessageBox.Show(ex.Message);
}
}
另请阅读:异常和异常处理,特别是异常概述和异常设计指南。