在按钮单击事件上刷新实时图表
Refreshing Live Chart on button click event
我有实时图表,我正在尝试对 Button_Click
事件执行新的值,但图表没有刷新。
我有两个 TextBoxes
,用户可以在其中 select 他们想要查看的开始和结束日期,并使用 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();
}
最好永远不要只为了更新某些属性的数据绑定而重置 DataContext
。这会导致非常糟糕的性能,因为完整的视图将被迫再次渲染。 DataContext
也沿元素树向下继承。
更好地编写更简洁的代码并更优雅地处理动态数据并按照框架的预期进行(参见 Data Binding Overview)。
在控件内部(或通常在 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);
}
}
另请阅读:异常和异常处理,尤其是 Exceptions Overview and Design Guidelines for Exceptions。
在调用 ChartValues()
或实施 INotifyPropertyChanged
之前设置 DataContext = null;
并从源属性的设置器引发 PropertyChanged
事件。
我有实时图表,我正在尝试对 Button_Click
事件执行新的值,但图表没有刷新。
我有两个 TextBoxes
,用户可以在其中 select 他们想要查看的开始和结束日期,并使用 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();
}
最好永远不要只为了更新某些属性的数据绑定而重置 DataContext
。这会导致非常糟糕的性能,因为完整的视图将被迫再次渲染。 DataContext
也沿元素树向下继承。
更好地编写更简洁的代码并更优雅地处理动态数据并按照框架的预期进行(参见 Data Binding Overview)。
在控件内部(或通常在 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);
}
}
另请阅读:异常和异常处理,尤其是 Exceptions Overview and Design Guidelines for Exceptions。
在调用 ChartValues()
或实施 INotifyPropertyChanged
之前设置 DataContext = null;
并从源属性的设置器引发 PropertyChanged
事件。