Silverlight : How to bind a result of loadoperation to LineSeries chart which contains few null values - wpf

I have bound a my chart to a result of load operation. The result returned by the load operation returns complex type with values for some of the object's properties is null.
So I am getting an error in my silver light application.
The code of my XAML is as follows:
<Grid x:Name="LayoutRoot">
<toolkit:Chart Name="historicalTotalChart" Title="Chart Title">
<toolkit:LineSeries >
</toolkit:LineSeries>
</toolkit:Chart>
</Grid>
Code of in my CS file is as follows:
LoadOperation<GetHistoricalTotalReport_Result> hisTotalsLoadOp =
context.Load(context.GetHistoricalToalReportQuery(tableName, sD, startDate, endDate));
LineSeries line = new LineSeries();
line.ItemsSource = hisTotalsLoadOp.Entities;
//line.DependentValuePath ="rep_date";
//line.IndependentValuePath = "expr1";
line.DependentValueBinding = new Binding("[rep_date]");
line.IndependentValueBinding = new Binding("[expr1]");
line.Title = "Historical Totals";
historicalTotalChart.Series.Add(line);
Can any one say how can I over come this error?
rep_date, expr1 are the properties with in my complex type GetHistoricalTotalReport_Result. I am I binding to the properties correctly?
Any help much appreciated.
Thanks

There are 3 possible issues in your application:
Your bindings shouldn't contain square brackets, they are for arrays and dictionaries. Also I would rather use the properties Dependent/IndependentValuePath, you shouldn't comment them, they are completely correct.
The DependentValuePath property must be of a numerical data type, because it is situated on the Y-axis. In your example the rep_date property could be of the double type.
The IndependentValuePath is situated on the X-axis and could be of any type but the values can't contain nulls. Really, I have no idea where a null value can be displayed on the X-axis, it doesn't make sense.
Here is the example of the correct code which works fine:
LineSeries line = new LineSeries();
line.ItemsSource = new[]
{
new ItemViewModel{expr1 = "Item1", rep_date = 25},
new ItemViewModel{expr1 = "Item2", rep_date = null},
new ItemViewModel{expr1 = "Item3", rep_date = 31},
new ItemViewModel{expr1 = "Item4", rep_date = null},
};
line.DependentValuePath = "rep_date";
line.IndependentValuePath = "expr1";
line.Title = "Historical Totals";
historicalTotalChart.Series.Add(line);
The next code will not work:
line.ItemsSource = new[]
{
new ItemViewModel{expr1 = null, rep_date = 25} //wrong, x-value can't be null
}
But you can filter your entities before displaying them:
line.ItemsSource = hisTotalsLoadOp.Entities.Where(e => e.expr1 != null).ToList();

Related

Create DataGrid in WPF at runtime

There is a DataGridView which is created at runtime with data fetching from database. There are four types of columns in data grid view:
DataGridViewTextBoxColumn
DataGridViewComboboxColumn
DataGridViewButtonColumn
DataGridViewCheckBoxColumn
Code for creating that datagridview is as below:
_form.DGV_.AutoGenerateColumns = False
_form.DGV_.Columns.Clear()
'Required Variables
Dim pom_DataGridViewTextBoxColumn As DataGridViewTextBoxColumn = Nothing
Dim pom_DataGridViewComboBoxColumn As DataGridViewComboBoxColumn = Nothing
Dim pom_DataGridViewButtonColumn As DataGridViewButtonColumn = Nothing
Dim pom_DataGridViewCheckBoxColumn As DataGridViewCheckBoxColumn = Nothing
'Column-1 (ID: jntDate)
pom_DataGridViewTextBoxColumn = New DataGridViewTextBoxColumn
pom_DataGridViewTextBoxColumn.DataPropertyName = "jntDate"
pom_DataGridViewTextBoxColumn.HeaderText = "Date"
pom_DataGridViewTextBoxColumn.DefaultCellStyle.Format = "d"
_form.DGV_.Columns.Add(pom_DataGridViewTextBoxColumn)
'Column-2 (ID: jntAcc)
pom_DataGridViewComboBoxColumn = New DataGridViewComboBoxColumn
pom_DataGridViewComboBoxColumn.DataPropertyName = "jntAcc"
'Cond: If dataset Acc does not contain any table then add table from database.
If Acc.Tables.Count > 0 Then
pom_DataGridViewComboBoxColumn.DataSource = Acc.Tables.Item(0)
Else
Acc.Tables.Add(Tbl_Select("SELECT *, accNo AS byNo, accName as byName FROM tblAccounts", False, ""))
pom_DataGridViewComboBoxColumn.DataSource = Acc.Tables.Item(0)
End If
'Cond: If _Account_Name_Number is True then set DisplayMember property to 'byName'.
If _Account_Name_Number Then
pom_DataGridViewComboBoxColumn.DisplayMember = "byName"
Else
pom_DataGridViewComboBoxColumn.DisplayMember = "byNo"
End If
pom_DataGridViewComboBoxColumn.ValueMember = "accID"
pom_DataGridViewComboBoxColumn.HeaderText = "Account"
_form.DGV_.Columns.Add(pom_DataGridViewComboBoxColumn)
'Column-3 (ID: xxxx)
pom_DataGridViewButtonColumn = New DataGridViewButtonColumn
pom_DataGridViewButtonColumn.DataPropertyName = "xxxx"
pom_DataGridViewButtonColumn.UseColumnTextForButtonValue = True
pom_DataGridViewButtonColumn.HeaderText = "X"
pom_DataGridViewButtonColumn.Text = "X"
pom_DataGridViewButtonColumn.Width = 32
pom_DataGridViewButtonColumn.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
pom_DataGridViewButtonColumn.DefaultCellStyle.ApplyStyle(pom_DataGridViewButtonColumn.DefaultCellStyle)
_form.DGV_.Columns.Add(pom_DataGridViewButtonColumn)
'Column-4 (ID: jntReview)
pom_DataGridViewCheckBoxColumn = New DataGridViewCheckBoxColumn
pom_DataGridViewCheckBoxColumn.DataPropertyName = "jntReview"
pom_DataGridViewCheckBoxColumn.HeaderText = "Review"
pom_DataGridViewCheckBoxColumn.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
pom_DataGridViewCheckBoxColumn.DefaultCellStyle.ApplyStyle(pom_DataGridViewCheckBoxColumn.DefaultCellStyle)
_form.DGV_.Columns.Add(pom_DataGridViewCheckBoxColumn)
In WPF application, there is a need to populate same DataGrid with these four columns.
How can I create and bind data to four types of columns in DataGrid in WPF ?
Why not skip doing all that stuff in cs code? You'll start pinning yourself in the corner and WILL hit the wall when the datagrid will need more complex templates, data triggers, custom styles, animations, etc... Besides, it will make it easier not only on the next person, but you as well. When you have to add/fix something in the beast you create in .cs code 3-6 months down the road, it might take you quite a while to understand what is going on :)
Instead, do all your work in xaml, Create a UserControl, put this datagrid in it, Pass the DataContext from various instances of the UserControl down to it's DataGrid.

Silverlight: DateTime format in TextBlocks

I'd like to use a custom DateTimeFormat across my entire Silverlight app, so I plugged in the following code in my App.xaml.cs.
var ci = (CultureInfo)Thread.CurrentThread.CurrentCulture.Clone();
ci.DateTimeFormat = new DateTimeFormatInfo()
{
ShortDatePattern = "dd/MM/yyyy",
LongDatePattern = "dd/MM/yyyy",
FullDateTimePattern = "dd/MM/yyyy HHmm\\h",
AMDesignator = string.Empty,
PMDesignator = string.Empty,
ShortTimePattern = "HHmm\\h",
LongTimePattern = "HHmm\\h"
};
Thread.CurrentThread.CurrentCulture = ci;
A DateTime.Now.ToString("f") gives me the answer I want (which is a 24-hour format DateTime string). However, when I do the following in XAML, the TextBlock ignores my CultureInfo and does its own thing:
<TextBlock Text="{Binding ArrivalTime,StringFormat=f}"/>
Does anybody know a way in which I can get the TextBlock to display in the format I desire? Many thanks...

Can't get two-way binding to work :)

I have a project which sets up dynamic tabs for monitoring and thus hosts several "identity" objects which are INotifyPropertyChanged and work individually as tested in a dummy app. However, I can't get the bindings to work correctly in the app I'm working on. They are set up i.e.:
(Configuration.Identities is an ObservableCollection<Identity>)
foreach (Identity id in Configuration.Identities)
{
workTab = new TabItem();
workSettingsTab = new SettingsTabItem();
workTab.DataContext = id;
Binding workTabHeaderBinding = new Binding("Username");
workTabHeaderBinding.Converter = new ToLowerConverter();
workTab.SetBinding(TabItem.HeaderProperty, workTabHeaderBinding);
workSettingsTab.DataContext = id;
Binding workSettingsTabHeaderBinding = new Binding("Username");
workSettingsTabHeaderBinding.Converter = new ToUpperConverter();
workSettingsTab.SetBinding(TabItem.HeaderProperty, workSettingsTabHeaderBinding);
This stuff above works fine, presumably because it's one-way. But these two only work one-way:
workSettingsTab.txtUsername.DataContext = id;
Binding usernameBinding = new Binding("Username");
usernameBinding.Mode = BindingMode.TwoWay;
workSettingsTab.txtUsername.SetBinding(TextBox.TextProperty, usernameBinding);
Binding getJournals = new Binding("LoadJournals");
scrapeJournals.Mode = BindingMode.TwoWay;
workSettingsTab.chkScrapeJournals.DataContext = id;
workSettingsTab.chkScrapeJournals.SetBinding(CheckBox.IsCheckedProperty, scrapeJournals);
I noticed when debugging my save-routine, that the Identity object referenced in DataContext in above controls does indeed contain the changed values, but the one in the ObservableCollection I used in the foreach above is not updated. So somehow the Identity object gets copied from the one initially used to set the DataContext property during the foreach. What am I doing wrong here?
Right. I can't get this to make sense, but so far:
ObservableCollection<SwitchClass> col2 = new ObservableCollection<SwitchClass>();
col2.Add(new SwitchClass{theSwitch=false});
col2.Add(new SwitchClass{theSwitch=true});
col2.Add(new SwitchClass{theSwitch=false});
col2.Add(new SwitchClass{theSwitch=true});
customTab cTab;
Int32 z = 0;
Binding b;
foreach (SwitchClass s in col2)
{
cTab = new customTab();
cTab.theCheckbox.DataContext = s;
b = new Binding("theSwitch");
b.Mode = BindingMode.TwoWay;
cTab.SetBinding(CheckBox.IsCheckedProperty, b);
cTab.Header = "Tab " + z.ToString();
z++;
tabControl.Items.Add(cTab);
}
Does not work, but:
ObservableCollection<SwitchClass> col2 = new ObservableCollection<SwitchClass>();
col2.Add(new SwitchClass{theSwitch=false});
col2.Add(new SwitchClass{theSwitch=true});
col2.Add(new SwitchClass{theSwitch=false});
col2.Add(new SwitchClass{theSwitch=true});
customTab cTab;
Int32 z = 0;
foreach (SwitchClass s in col2)
{
cTab = new customTab();
cTab.DataContext = s;
cTab.Header = "Tab " + z.ToString();
z++;
tabControl.Items.Add(cTab);
}
with
<CheckBox Name="theCheckbox" Width="200" Height="50" Content="Checkbox" IsChecked="{Binding theSwitch}" />
works perfectly. I suppose this is just a limitation of WPF?

Set DisplayMemberPath and SelectedValue in WPF with Code

I have a DataTable that is coming from a Web Service, which I need to bind to a ComboBox. I have not grokked doing binding in XAML yet so this question is about binding in code instead. So far I have tried
cboManager.DataContext = Slurp.DistrictManagerSelect().DefaultView;
cboManager.DisplayMemberPath = "Name";
cboManager.SelectedValuePath = "NameListId";
cboManager.SetBinding(ComboBox.ItemsSourceProperty, new Binding());
And I have tried
DataTable tbl = new DataTable();
tbl = Slurp.DistrictManagerSelect();
cboManager.ItemsSource = ((IListSource)tbl).GetList();
cboManager.DisplayMemberPath = "[Name]";
cboManager.SelectedValuePath = "[NameListId]";
DataContext = this;
In both cases I get the list of managers to show but when I select from the ComboBox I get [Name] and [NameListId] and not the values I am expecting. What am I doing wrong (other than not using XAML's DataBinding)?
Edit added after answers to my original post came in.
So (based on Rachel's response) try number three looks like this:
using (DataTable tbl = Slurp.DistrictManagerSelect())
{
List<ManagerList> list = new List<ManagerList>();
foreach (var row in tbl.Rows)
{
list.Add(new ManagerList
{
NameListId = (int)row[0],
Name = row[1].ToString()
});
}
}
Assuming I am doing what she meant the correct way I am no getting this error Cannot apply indexing with [] to an expression of type 'object'
Have you tried to just bind to the DataTable directly? Do you have columns Name and NameListId? Leave off the DataContext (you already assigned the ItemsSource).
DataTable tbl = Slurp.DistrictManagerSelect();
cboManager.ItemsSource = tbl;
cboManager.DisplayMemberPath = "Name";
cboManager.SelectedValuePath = "NameListId";
When you cast to the IListSource I suspect it is combining all the columns. If you want to bind to a list then you need to create items that have properties Name and NameListID.
I think that's because your ItemsSource is a DataTable, so each ComboBoxItem contains a DataContext of a DataRow, and the DataRow class doesn't have properties called Name or NameListId
Basically, you're trying to tell the ComboBox to display DataRow.Name, and set the value to DataRow.NameListId, both of which are not valid properties.
I usually prefer to parse data into objects, and bind the ItemsSource a List<MyObject> or ObservableCollection<MyObject>
foreach(DataRow row in tbl.Rows)
list.Add(new MyObject { Name = row[0].ToString(), NameListId = (int)row[1] });
cboManager.ItemsSource = list;

How do you format in code AxisLabel for DependentRangeAxis?

I cannot get the axis to format as currency, any idea?
What am I doing wrong? I need to be able to change the formatting on the fly and for this test I wanted to set it as currency for the Y axis on the scale of values.
Anyone?
Thanks...
var columnSeries = new ColumnSeries
{ Title = reportProcedureNode.Value,
IndependentValuePath = "PrimaryKey",
DependentValuePath = "Value",
IndependentAxis = new CategoryAxis { Orientation = AxisOrientation.X, ShowGridLines = false, Location = AxisLocation.Bottom},
DependentRangeAxis = new LinearAxis(){Orientation = AxisOrientation.Y, ShowGridLines = false}
};
var labelStyle = new Style(typeof(AxisLabel));
labelStyle.Setters.Add(new Setter(AxisLabel.StringFormatProperty, "{}{0:C0}"));
var axis = (LinearAxis)columnSeries.DependentRangeAxis;
axis.AxisLabelStyle = labelStyle;
In my WPF4 version of the charting toolkit, your code crashes. I needed to change:
labelStyle.Setters.Add(new Setter(AxisLabel.StringFormatProperty, "{}{0:C0}"));
to:
labelStyle.Setters.Add(new Setter(AxisLabel.StringFormatProperty, "{0:C0}"));
That is, remove the {}. The {} comes from markup extension syntax:
{} Escape Sequence / Markup Extension
and is only needed when being parsed by XAML as a markup extension inside "{...}".
Since you are setting the property directly, no markup extension is involved and including it prevents the real currency format from being seen.

Resources