I have three ListBoxes (CompanyName, Representative & QuoteNumber) and I load data from my WCF client, into the CompanyName list box using the method below:
private async Task LoadCompanies()
{
using (TruckServiceClient client = new TruckServiceClient())
{
var companies = await client.GetCompaniesAsync();
foreach (var company in companies)
lbxCompanyName.Items.Add(new ListBoxViewItem<Company>(company));
}
}
Now in the coding below I allow myself to select the Company Name in the lbxCompanyName ListBox and then viewing the Representatives that belongs to that Company in my lbxRepresentative ListBox.
private void lbxCompanyName_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var company = (ListBoxViewItem<Company>)lbxCompanyName.SelectedItem; //Changing this line to auto select an Item for me
foreach (var rep in company.Item.Represetatives)
lbxRepresentatives.Items.Add(new ListBoxViewItem<Represetative>(rep));
}
What I want to achieve is to auto/programmatically select the name, let's say "Josh", from the CompanyName ListBox. How would I go about doing this with the coding that I have now?
Basically I want to hide my listboxes and let my program select everything for me.
With data binding you can bind the ItemsSource and SelectedItem
Then you can just assign the SelectedItem in code behind
You most likely will need to implement INotifyPropertyChanged
And you can populate Representative with binding
But what you have is strange - you just keep added Represetatives with each SelectionChanged
For testing purposes I solved my issue by setting my first two ListBoxes (CompanyName, Representative)SelectedIndex to 0 and then using the coding below for my last ListBox (QuoteNumber) to select the last inserted row in my QuoteNumber listbox.
if (lbxQuoteNumber.Items.Count > -1)
lbxQuoteNumber.SelectedIndex = lbxQuoteNumber.Items.Count - 1;
Thanks for all the help dudes! :)
Related
I fill datagrid from DataBase using sqlite - ShowDataBase(string a);
Then I want to sort It,When Button is Clicked
(Note! I want to sort it only in program(not modding the DB). Just want to delete wrong rows)
private void Button_Click(object sender, RoutedEventArgs e)
{
ShowDataBase("Pacients");
if ((bool)SortFromCheckBox.IsChecked)
{
//Delete all data earlier than data that user asked for
for (int i = DataGridMain.Items.Count - 1; i >= 0; i--)
{
DataGridRow row = (DataGridRow)DataGridMain.ItemContainerGenerator.ContainerFromIndex(i);
var item = DataGridMain.Items[i];
var data = DataGridMain.Columns[4].GetCellContent(item);
if ((Convert.ToDateTime(data)) <= (Convert.ToDateTime(SortFromTextBox.Text)))
{
//Smth to delete row № i from datagrid
}
}
}
if ((bool)SortUntilCheckBox.IsChecked)
{
//Delete all data older than data that user asked for
}
if ((bool)SortByClientCheckBox.IsChecked)
{
//Delete all data where client cell is != name that user want to sort by
}
if ((bool)SortByDoctorCheckBox.IsChecked)
{
//Delete all data where doctor cell is != name that user want to sort by
}
}
From what I understand you need a functionality to filter and sort the data. You could make use of a build in mechanics for that purpose: CollectionView. You need to create one which source will be set to the data you get from database.
To filter the collection you can use the collectionView.Filter and define different filters for your purposes. For Sorting functionality you should make use of collectionView.SortDescriptions. This way you utilize the tools already present in .NET that you only need to customize for your needs.
With this approach, you don't remove anything from base collection, so you need to get the data only once and present it in different ways in your application. If you are using MVVM approach, this code should be done in the ViewModel. If you insist on achieving such functionality in your View, you could play with <CollectionViewSource>.
You can find some resources here:
Dr.WPF: ItemsControl: 'C' is for Collection
Dr.WPF: ItemsControl: 'E' is for Editable Collection
MSDN: How to: Group, Sort, and Filter Data in the DataGrid Control
I'm writing a WPF application connected to a local Access database. In one of the application screens, one table data (named Service) is shown in individual textboxes, like a form, and the user can navigate through records, create new ones, delete, edit or search. Everything is done on the same table.
After a intensive research on how to navigate through records displayed in textboxes, I ended up using a DataSet and a CollectionView.
public partial class Entries : Window
{
AgendaDataSet agendaDataSet = new AgendaDataSet();
AgendaDataSetTableAdapters.ServiceTableAdapter serviceAdapter = new AgendaDataSetTableAdapters.ServiceTableAdapter();
CollectionView workSheetView;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.serviceAdapter.FillByDateAsc(agendaDataSet.Service);
this.DataContext = agendaDataSet.Service;
this.workSheetView = (CollectionView)CollectionViewSource.GetDefaultView(agendaDataSet.Service);
this.workSheetView.MoveCurrentToLast();
}
I got record navigation working using the CollectionView methods MoveCurrentToFirst(), MoveCurrentToNext(), etc. I also can create new records, edit and delete.
This is the method I use to create a new record:
private void btnNovo_Click(object sender, RoutedEventArgs e)
{
dynamic row = this.agendaDataSet.Service.NewMainRow();
this.agendaDataSet.Service.AddMainRow(row);
this.workSheetView.MoveCurrentToLast();
}
My problem is with record searching. I have a button that, when the user presses it, it asks for the PatientName he is searching. Then, the data about that Patient must appear on the various textboxes, ready to be consulted, edited or deleted.
Through the CollectionView, I only found the method GetItemAt() that gets a record based on it's row index. Since I am working with an Access database, I can't use the predicate ROW_NUMBER. And I don't think this approach would be the best.
So, how can I get an item based on it's ID, or PatientName, or any other field, and pass it as a row to the CollectionView?
Probably you don't need to get an item based on its ID or PatientName property.
Suppose that the user looks for "Andrew" as PatientName. Your code finds that the second row of your DataTable (called "Service") is the one the user is looking for.
You can use a simple static method to look for a DataRowView, something like this:
private static DataRowView FindDataRowView(DataView dataView, DataRow dataRow)
{
foreach (DataRowView dataRowView in dataView)
{
if (dataRowView.Row == dataRow)
{
return dataRowView;
}
}
return null;
}
and then you can select the object in your CollectionView:
collectionView.MoveCurrentTo(FindDataRowView(agendaDataSet.Service.DefaultView,
agendaDataSet.Service.Rows[2]));
Of course you can find the real DataRow index by using a foreach cycle or the Select method of DataTable.
At the moment I have method I created so that when you click anything in the Treeview, the method will activate.
private void MyTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
cAuditTasksEntity task = new cAuditTasksEntity();
cAuditTasksEntity entityTask = MyTreeView.SelectedItem as cAuditTasksEntity;
}
This is my To-Do-list, When they select something from anything in the list of _Pot which on the picture includes Acceptance Pot 1 Acceptance Pot 2, I need it to return that SelectedItem.
With that SelectedItem in a variable I can get the PolicyNumber and search the database for that Task(the SelectedItems) details.
EDIT:
I have added this code:
var Info = MyTreeView.SelectedItem;
I know it will do any SelectedItem in the TreeView but I can add an IF statement around it, this reads the Date & PolicyNumber from the picture I shown with that how can I get the PolicyNumber and find the TransactionType that matches that Policynumber.
One solution would be to create a SelectedItem property on your view model. You can then bind your SelectedItem to this property in xaml:
<... SelectedItem={Binding SelectedItem} />
You can then access this within the method you have defined.
I have a program with a class called MyClass and Location. MyClass contains an ObservableCollection of Location items and Location contains a string property called Name. In MainPage.xaml I have a LongListSelector (with a ContextMenu for each item) populated with grids representing a Location.
When I click the 'remove' menu item from the context control, it will usually remove the underlying Location object and update the view. After a few cycles of populating the LongListSelector and removing all its items, some new items that are added can't be removed anymore.
Here's an example of what I mean: The LLS originally contains 2 items. Then I delete those 2 items and add 3 more. However, I can only remove the third one, in this case, but not the first 2.
Here's the ContextMenu MenuItem click event from MainPage.xaml.cs:
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
var selectedItem = (sender as MenuItem).DataContext as Location;
for (int i = 0; i < MyClass.Locations.Count; i++)
{
if (MyClass.Locations[i].Name == selectedItem.Name)
{
MyClass.Locations.Remove(MyClass.Locations[i]);
break;
}
}
}
Prior to using a for loop, I used this LINQ code and still had the same problem:
var toRemove = MyClass.Locations.Where(x => x.Name == selectedItem.Name).SingleOrDefault();
MyClass.Locations.Remove(toRemove);
Any suggestions to fix this problem?
I suggest you to use a ListBox instead of LLS - if you are not using grouping option. It works much better and causes less problems.
By the way I've also encountered some problems with this Control - maybe similar to yours. Weird is also that LLS.UpdateLayout() doesn't work while in ListBox works perfect.
I have a windows forms application containing a datagridview control. The datagridview is populated by the contents of an xml file. At the moment, all of the columns are displayed as datagridviewtextboxcolumns. I want to select one that is populated by a particular xml tag and display it's content in a datagridviewcomboboxcolumn along with 2 other options.
EXAMPLE:
<SMS>
<Number>+447931663542</Number>
<DateTime>2009-07-12T17:00:02</DateTime>
<Message>YES</Message>
<FollowedUpBy>Unassigned</FollowedUpBy>
<Outcome>Resolved</Outcome>
</SMS>
The OUTCOME tag is the column that I would like to be displayed as a comboboxcolumn in the datagridview. If for example the tag is empty and contains no data, then I want to display nothing, but have the comboboxcolumn populated with 3 possible options to choose from (Unresolved, Resolved, Pending). If however the tag contains data, I want that particular item to be displayed in the comboboxcolumn, and have the other two options available to be selected.
Help in achieving this would be appreciated greatly!
Regards,
EDIT:
Currently I use this code:
colOutcome = new DataGridViewComboBoxColumn();
colOutcome.HeaderText = "Outcome";
colOutcome.Width = 90;
colOutcome.Items.AddRange("Resolved", "Unresolved", "Pending");
this.dataGridView1.Columns.Insert(1, colOutcome);
this.dataGridView1.Columns[1].Name = "OutcomeColumn";
This code above populates the combobox. THE PROBLEM IS: When The xml document populates the datagridview, the outcome column just appears as a textbox column, containing the data inbetween the outcome tags in the xml file. My point is, how can i get the datagridview to realise when it reads the outcome column that it needs to be changed into a combobox column and then display the data that way, along with the other potentially selectable options in the combobox?! Currently the datagridview gets populated with all columns as textboxcolumns containing the data, as well as a seperate combobox column which is not what I want. I need the application to merge the outcome column and its data with the code above.
Any ideas?
Updated Answer
You could pass in the XML document to a function that will loop through each node and determine whether it should be a ComboBox one or not i.e. if the name is "Outcome".
private void CreateColumns(XmlDocument doc)
{
foreach (...) // loop through each node in xml document
{
if (node.Name == "Outcome")
{
var items = new List<string>() { "Resolved", "Unresolved", "Pending" };
this.dataGridView1.Columns.Add(CreateComboBoxColumn(node.Name, items));
}
else
{
this.dataGridView1.Columns.Add(String.Format("col{0}", node.Name), node.Name);
}
}
}
Then your code for creating the Outcome column would be:
private DataGridViewComboBoxColumn CreateComboBoxColumn(string colHeaderText, List<string> items)
{
var colOutcome = new DataGridViewComboBoxColumn();
colOutcome.HeaderText = colHeaderText;
colOutcome.Width = 90;
colOutcome.Items.AddRange(items.ToArray());
colOutcome.Name = String.Format("col{0}", colHeaderText);
return colOutcome;
}
You would then just call CreateColumns on the form load event and pass in your XML. You should only need to create the columns once.
My advice would be to have a similar function that will find all the SMS elements and add a new row populating it with the information in each node.
public void MyForm_Load(object sender, EventArgs e)
{
var doc = new XmlDocument(filename);
CreateColumns(doc);
CreateRows(doc);
}
Hope that helps.
Answer #2 for me, based on the updated question.
The problem you are experiencing is with the AutoGeneratedColumns functionality of the DataGridView. You will need to create your columns manually before databinding. This can be done at design-time or run-time. I prefer design-time because it gives you a bit more direction with the look/feel of the grid but either way works.
You will need to disable the AutoGeneratedColumns property of the grid:
private void Form1_Load(object sender, EventArgs e)
{
// Define your columns at run-time here if that's what you prefer
this.dataGridView1.AutoGeneratedColumns = false;
this.dataGridView1.DataSource = myDataSource;
}
I'm not sitting in front of VS so this might not compile but should give you direction.
You need to either pre-populate the ResolvedColumn with the 3-4 possible values at design-time or assign it to another datasource at runtime. If you chose the design-time approach, simply open the DataGridView "Edit Columns" dialog, find the ResolvedColumn, go to Items, and add your values ("", "Unresolved", "Pending", "Resolved"). The empty value might help the ComboBox to render if there is the possiblity of rendering the grid with SMS records that have no Outcome.
To bind the possible options at runtime do something like this:
private List<string> _outcomeDataSource;
private void Form1_Load(object sender, EventArgs e)
{
_outcomeDataSource = new List<string>;
_outcomeDataSource.Add("");
_outcomeDataSource.Add("Unresolved");
_outcomeDataSource.Add("Pending");
_outcomeDataSource.Add("Resolved");
ResolvedColumn.DataSource = _outcomeDataSource;
ResolvedColumn.PropertyName = "Outcome";
}