Create binding in code from xml data - c#

I want to bind data from sample data to code in c#. I am not getting exact output when tried different models available online. I want to do arithmetic operation between two values from data table.
My xml data looks like this:
<SampleData:data xmlns:SampleData="clr-namespace:Expression.Blend.SampleData.data"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<SampleData:data.factors>
<SampleData:cfsItem col1="item1" item1="1" item2="2" />
<SampleData:cfsItem col2="item2" item2="3" item2="4" />
</SampleData:data.factors>
</SampleData:data>
I want to select the value with a LINQ query; i.e selecting col1 from table 'factors' in data and compare it with value returned from listbox element.
private void ListBox1_Tap(object sender, GestureEventArgs e)
{
ListBoxItem selected = ListBox1.SelectedItem as ListBoxItem;
string y = selected.Content as string;
this.DataContext = from factors in data
where col1.factors == y
select item1;
}
Can anyone help me out of this? Thank you!

It looks like your data object is a single item and that you're really looking for factors inside data.Based on what you show you would probably need the following to select the factors based on the ListBox.SelectedItem's content compared to the col1 property.
Just as a note: I think you meant the first item2 in the second record to really mean item1. If so the following would apply:
private void ListBox1_Tap(object sender, GestureEventArgs e)
{
var selectedItem = (ListBoxItem)ListBox1.SelectedItem;
if (selectedItem != null)
{
var y = (string)selectedItem.Content;
var filteredFactors = (from factor in data.factors
where factor.col1 == y
select factor.Item1);
//filteredFactors is IEnumerable
this.DataContext = filteredFactors;
// if you need the first only or nothing if there is none.
this.DataContext = filteredFactors.FirstOrDefault();
// if there can be nothing or only one
this.DataContext = filteredFactors.SingleOrDefault();
}
}
In the example above I selected only item1 of the filtered factors.
If you want to return the entire record you would remove .item1 in the query.
var filteredFactors = (from factor in data.factors
where factor.col1 == y
select factor);
You'll probably notice I have used the keyword var multiple times. I like to use it if it improves readability. see Implicitly Typed Local Variables if you're interested.

Related

How do I bind row count of a datagrid to a textblock text whose specific column has specific values?

I have a datagrid in my WPF c# application (MVVM pattern) whose ItemsSource is bound to a ICollectionView, something like :
public ICollectionView PendingBills { get; private set; }
public BillsViewModel()
{
_penBills = m.PBills;
PendingBills = new ListCollectionView(_penBills)
{
Filter = o => ((Bills)o).PaidOn==""
};
}
....
<DataGrid ItemsSource="{Binding PendingBills}"
Now I've bound the row count of the datagrid to a textblock text using something like (which shows the count of all rows after filter)
<TextBlock Text="{Binding PendingBills.Count, StringFormat='Total Pending Bills :\ {0}'}" ...
But I also want to bind the row count to a different textblock where say the BillNo column data of the database has a specific text or maybe its null or non-empty something like that.
How do I do that ? Do I need to use some sort of IValueConverter to this and if yes how ?
UPDATE
I've tried to a property to the viewmodel like
private int _cnt;
public int Cnt
{
get
{
if (_cnt == 0) _cnt = _penBills.Where(x => !String.IsNullOrEmpty(x.PaidOn.ToString())).Count();
return _cnt;
}
set
{
_cnt =value;
}
}
and then use it like Text="{Binding Cnt}" but it does not work.
While you could always use a converter yes (and this is my own opinion based on experience here) you may just want to do this in the code behind.
You could have a property stored that gets the count you are looking for based on a linq query and simply bind to that.
Let me give an example.
you could get back the elements that match on some text:
var countOfMatches = yourlist.Where(x => x.SOMEVALUE == SOMETEXT).Count();
or you could go by some numeric condition:
var countOfMatches = yourList.Where(x => x.Price > 400).Count();
I hope this is a helpful answer to you.
In short I am pretty much saying that if you want a custom count based on this list you are better off creating a property for it and setting it with a query.
Based on your edit:
change the query to:
_penBills.Where(x => x.PaidOn.ToString() != string.Empty).Count();
(which is just a nitpick really)
as for your binding can you confirm that the observable collection for bills and this new integer property are stored on a view model that is the data context for this xaml.cs view?

I'm getting "System.Collections.Generic.List" instead of data from database

I'm working on a project to develop a UWP app. I have implemented Sqlite database to store information about products.
I have a combobox in my page that displays the serial number of all the products. I've written the code for SelectionChanged event of the combobox as:
private void InvoiceSerial_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var a = conn.Query<Product>
("select brand from product where serial=?", InvoiceSerial.SelectedItem.ToString());
InvoiceBrand.Text = a.ToString();
}
But instead of displaying the brand name, I'm getting this:
System.Collections.Generic.List`1[MyProject.Inventory+Product]
InvoiceBrand is a textbox
Even if the result of an SQL query is exactly one row and one column, query functions in any language are still required to return a full table, to handle the general case where a resultant table has multiple items. The object you're looking for should be the first object in the list.
Your a variable is probably of type List<MyProject.Product>, and that's why calling a.ToString() returns the string representation of the type!
What you should probably be doing is retrieving the first element (just use a[0]) and then output the value of the "brand" field.
Ok so I got it to work thanks to #TimSchmelter
Now my code looks like this:
private void InvoiceSerial_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var a = conn.Query<Product>
("select brand from product where serial=?", InvoiceSerial.SelectedItem.ToString());
Product p = a.FirstOrDefault();
InvoiceBrand.Text = p.Brand;
}

Combobox returns null when value is typed

Sorry if it has some obvious solution, but I am trying to solve it for hours but could not find a solution.
I use several ComboBoxes in my WindowsFormsApplication to relate ids with names. The problem is that when a user select an item from the combobox list, it works fine, but when he types an item, the SelectedValue property of the combobox is null.
To simulate the problem, I created a from with one button and a combobox.
In my actual application, I populate the comboboxes with data from tables in a sqlserver database, but for simplicity, here I populate it with a list:
public Form1()
{
InitializeComponent();
List<KeyValuePair<short,short>> l = new List<KeyValuePair<short,short>>();
l.Add(new KeyValuePair<short,short>(1,10));
l.Add(new KeyValuePair<short,short>(2,20));
l.Add(new KeyValuePair<short,short>(3,30));
this.comboBox1.DataSource = l;
this.comboBox1.DisplayMember = "Value";
this.comboBox1.ValueMember = "Key";
}
private void button1_Click(object sender, EventArgs e)
{
if (this.comboBox1.SelectedValue == null)
MessageBox.Show("NULL");
else
MessageBox.Show(this.comboBox1.SelectedValue.ToString());
}
For example, when user select the second item (20) from the list and clicks on the button, messagebox shows 2 as it is expected, but if he types the number 20 into the combobox, the SelectedValue is null.
This problem could be solved by changing the style of combobox:
this.comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
But it prevents user to type into the combobox, so I am forced to use the default ComboBoxStyle.DropDown.
Thats because the combo box does not select the item that you have typed. Add this option
comboBox1.AutoCompleteMode = AutoCompleteMode.Suggest;
Then it will select the item when ever it was able to find it.
By default it is set to AutoCompleteMode.None.
(I think) This is mainly designed for suggestions but it can solve your problem here. also if you want to show the suggestions:
comboBox1.AutoCompleteSource = AutoCompleteSource.ListItems;
by default it is set to AutoCompleteSource.None.
https://msdn.microsoft.com/en-us/library/system.windows.forms.combobox.autocompletemode%28v=vs.110%29.aspx
An option that you have is using the EventHandler on the comboBox1.TextChange event that will allow you to personally handle how the text is translated into the different options.
This can be added to the designer (similar to a button).
this.comboBox1.TextChanged += new System.EventHandler(this.UpdateValue);
Then depending on how want to read the results and see if you have a match you can create a converter, use another key/value, or you can do a boring old tryparse as I will show you. You will need the list as a property that you can reference to see if you have found the proper results.
private void UpdateValue(object sender, EventArgs e)
{
short result;
if (short.TryParse(comboBox1.Text, out result))
{
var matches = from val in l where val.Value == result select val.Key;
{
foreach (short m in matches)
this.comboBox1.SelectedValue = m;
}
}
}
Good luck! Let me know if you need more examples with the event handler. Don't forget to vote.

Silverlight C#: How to filter a combobox based on another combobox?

How to filter a combobox based on another combobox? ... again :)
I'm writing an web app to learn. I'm using Visual Studio 2012, Silverlight 5, C#, and SQl Server for the data source.
I have one table loading into a datagrid and comboboxes to filter the datagrid. Up to this point everything is working just right.
The comboboxes are "FilterState" and "FilterWaterWay". Note they are not in the datagrid.
I want to select a state and re-populate the FilterWaterWay with only those waterways in the state.
I've seen a lot of ways to do this but none of them seem to match my setup. I could be wrong and just not know it.
From a learning standpoint, I would like to know how to implement this in all 3 of the following query data examples but I'll settle for just one. The last one is my favorite.
Thanks for any and all help.
I would not mind using the following to load comboboxes, filtered or not, but I can't firgure out how to
Restirct the GetQuery to only one field
Make that field distinct
This loads all data from the GetQuery to the datagrid.
LoadOperation<MASTER_DOCKS> loadOp = this._DocksContext.Load(this._DocksContext.GetMASTER_DOCKSQuery());
DocksGrid.ItemsSource = loadOp.Entities;
This loads all data from the GetQuery to the datagrid after it's been filtered
EntityQuery<MASTER_DOCKS> query = _DocksContext.GetMASTER_DOCKSQuery();
query = query.Where(s => s.WTWY_NAME == WaterwaytoFilterBy && s.STATE == StateToFilterBy);
LoadOperation<MASTER_DOCKS> loadOp = this._DocksContext.Load(query);
DocksGrid.ItemsSource = loadOp.Entities;
This is how I am currently loading the comboboxes. This works fine for the load but I don't see how to filter.
The DomainService.cs does not know my other combobox (FilterState) that I want to use as the filter for this combobox (FilterWaterway).
If I could query the ObservableCollection in the xaml I might be able to get it to work but it seems kind of chunky.
Adapted from http://www.jonathanwax.com/2010/10/wcf-ria-services-datagrid-filters-no-domaindatasource-2/
XAML =
private ObservableCollection<string> waterWayFilterList;
public ObservableCollection<string> WaterWayFilterList
{
get { return waterWayFilterList; }
set { waterWayFilterList = value; }
}
private void DoPopulateFilter()
{
//Call Invoke Method to get a list of distinct WaterWays
InvokeOperation<IEnumerable<string>> invokeOp = _DocksContext.FillWaterWayList();
invokeOp.Completed += (s, e) =>
{
if (invokeOp.HasError)
{
MessageBox.Show("Failed to Load Category Filter");
}
else
{
//Populate Filter DataSource
WaterWayFilterList = new ObservableCollection<string>(invokeOp.Value);
//Add a Default "[Select]" value
WaterWayFilterList.Insert(0, "[Select WaterWay]");
FilterWaterWay.ItemsSource = WaterWayFilterList;
FilterWaterWay.SelectedItem = "[Select WaterWay]";
}
};
}
DomainService.cs =
[Invoke]
public List<string> FillWaterWayList()
{
return (from r in ObjectContext.MASTER_DOCKS
select r.WTWY_NAME).Distinct().ToList();
}
Here's the closest I've gotten so far and it seems straight forward.
It returns no errors but the displayed result reads System.Collections.Generic.List'1[System.Char]
The record count in the dropdown is correct which leads me to think it's on the right track.
Only what is displayed is wrong. A casting problem perhaps?
I would still have to get the result from the FilterState Combo box in where "TX" is.
var filter = from r in _DocksContext.MASTER_DOCKS
where r.STATE.Equals("TX")
select r.WTWY_NAME.Distinct().ToList();
MyComboBox.ItemsSource = filter;
Without parentheses, you're doing the .Distinct().ToList() on the string (which implements IEnumerable<char>, which is why those operations work), which results in a List<char> (which isn't what you're looking for). You need to add parentheses so you get the distinct waterways:
var filter = (from r in _DocksContext.MASTER_DOCKS
where r.STATE.Equals("TX")
select r.WTWY_NAME).Distinct().ToList();
Note that if two waterways might have the same name, but actually be distinct, you'll need to instead select distinct r, and then differentiate them in the dropdown somehow, e.g.
var filter = (from r in _DocksContext.MASTER_DOCKS
where r.STATE.Equals("TX")
select r).Distinct().ToList();
// generated classes are partial, so you can extend them in a separate file
public partial class MASTER_DOCKS
{
// the dropdown uses the ToString method to show the object
public override string ToString()
{
return string.Format("{0} ({1})", WTWY_NAME, ID);
}
}

Binding BindingList<string[]> to datagridview

Situation:
I am attempting to bind a BindingList<string[]> constructed from a LINQ to SQL query to a DataGridView.
Problem:
I either cannot make modification to the DataGridView after items are generated -or- I get a bunch of unwanted fields in my DataGridView (it depends on which iteration of my code I use) I have googled as hard as I can and tried implementing most of the solutions I have found online to no avail.
I know that string has no public property for its actual value. I am having a difficult time determining how to retrieve that (I believe is part of the problem).
C#
int item = (from p in CurrentConversion.Companies[lbCompanies.SelectedIndex].Modules
where p.ModuleName.Equals(clbModules.SelectedItem)
select p.ModuleId)
.FirstOrDefault();
BindingList<string[]> Data = new BindingList<string[]>((
from p in CurrentConversion.Companies[lbCompanies.SelectedIndex].QuestionAnswers
where p[2].Equals(item)
select new string[] { p[0].ToString(), p[3].ToString() })
.ToList());
dgvQuestions.DataSource = Data;
dgvQuestions.Refresh();
Unwanted Behavior:
This occurs after binding
Question:
Why is this happening?
How do I fix it?
Additional Information:
I am not sure what additional information may be need but I will supply what is requested.
Also if I switch to my other code iteration:
int item = (from p in CurrentConversion.Companies[lbCompanies.SelectedIndex].Modules where p.ModuleName.Equals(clbModules.SelectedItem) select p.ModuleId).FirstOrDefault();
var Data = new BindingList<object>((from p in CurrentConversion.Companies[lbCompanies.SelectedIndex].QuestionAnswers where p[2].Equals(item) select new {Question = p[0].ToString(), Answer = p[3].ToString() }).Cast<object>().ToList());
dgvQuestions.DataSource = Data;
dgvQuestions.Refresh();
dgvQuestions.Columns[1].ReadOnly = false;
I can see the data properly but I cannot edit the column I would like to.
You are binding to a list of string arrays, and you are getting the properties form the array. Most likely you want something like the following:
var Data = new BindingList<object>((
from p in CurrentConversion.Companies[lbCompanies.SelectedIndex].QuestionAnswers
where p[2].Equals(item)
select new {
Val1 = p[0].ToString(),
Val2 = p[3].ToString()
}).ToList());
The reason you're seeing those fields in the Grid is that you're binding each row to a string[]. So it is automatically displaying the properties of string[] as the columns. There is no built-in logic for the grid to parse an array and use the contents of the array as columns.
In order to get the DataGrid to display your data correctly, you should bind it to a custom type, and it will use the public properties of the type as columns.

Categories