Exception for finding the SelectedItem in a Treeview? - c#

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.

Related

How to preserve two way binded value when changing both datacontext and items source of WPF ComboBox

Background
The application has a list view binded to a list of "Jobs", of which the properties are editable by some comboboxes (with two way binding). The data context of the comboboxes is changed to the currently selected job via the SelectionChanged event of the list view.
The combobox value is bound to a property of Job. The itemssource of the job is changed to completely different list upon DataContextChanged.
Layout of widgets
Issue
The binded property linked to the combobox of Job is set to null when changing the DataContext.
By clicking through the list of Jobs, all the properties bound to any combobox are set to null.
Assumed Problem
I may be incorrect in this assumtion...
As the datacontext is switched, either the old selected Job or the new selected Job is set to null as the itemsource does nto contain the value stores in on of the either the new or old selected Job.
Debugging Attempts (Edit)
I've noticed the the value of the property of the Job was set to null before the SelectedItem of the list of jobs was changed.
Question
How can the value of the binded property of Job be preserved when switching the datacontext of the ComboBox to an itemsource that does not contain SelectedValue?
Relevant Code (Abridged - Binding to other widgets works as expected)
<ComboBox x:Name="ContactField" Grid.Column="1" Grid.Row="3" Margin="2,1" Grid.ColumnSpan="3" DisplayMemberPath="Value" SelectedValuePath="Id" SelectedValue="{Binding Contact,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectionChanged="ContactField_SelectionChanged"/>
Code Behind - Changing Items Source
private void UpdateCustomerDependancies()
{
imprintDataSetTableAdapters.CustomerContactsTableTableAdapter rpcdtta = new imprintDataSetTableAdapters.CustomerContactsTableTableAdapter();
IList<ComboData> customers = new List<ComboData>();
if (LeftFieldPanel.DataContext != null) //Where LeftFieldPanel contains all comboboxes
{
Job currentJob = (Job)LeftFieldPanel.DataContext;
foreach (DataRow item in rpcdtta.GetDataBy(currentJob.CustomerCode).Rows)
{
customers.Add(new ComboData() { Id = item.ItemArray[0].ToString(), Value = item.ItemArray[1].ToString() });
}
ContactField.ItemsSource = customers;
}
}
Code Behind - Changing Data Context
private void jobTree_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (jobTree.SelectedItem.GetType() == typeof(Job))
{
DelGrid.Visibility = Visibility.Hidden;
Job j = (Job)jobTree.SelectedItem;
MessageBox.Show(j.Contact);
LeftFieldPanel.DataContext = j; //Switch datacontext
RightFieldPanel.DataContext = j; //switchdata context
}
}
According to this answer, and my own research, it is not possible to simply bind and hope for this best. Therefore, my workaorund to this solution is the following. I have generalised the code to make it applicable to other circumstances.
1) Upon the change of datacontext, append new items to the list, without removing old items:
private void ListView1_SelectedItemChanged(...) {
List<ComboData> comboitems = ((IList<ComboData>)ComboBox1.ItemsSource).ToList();
//Add new items to comboitems here
ComboBox1.ItemsSource = comboitems; //Rebind
}
2) Upon opening the dropdown of the combobox, get the itemsource and remove old items only
private void ComboBox1_DropDownOpened(...) {
List<ComboData> comboitems = ((IList<ComboData>)ComboBox1.ItemsSource).ToList();
//Remove old items from comboitems here
ComboBox1.ItemsSource = comboitems; //Rebind
}
Apologies if this is not clear enough, I felt that posting the real code would make it rather difficult to understand out of the context.
This has solved my own issue.
Alternate Solution
See above and add items without remove old ones. Then replace the entire itemssource only on a dropdownopened event.

Treeview.Items.Clear() method return null exception (e.NewValue==null) in SelectedItemChanged Event

I am from Iran and I cant speak English very well, sorry.
I made something like OpenFileDialog in WinForms
and work correctly.
After, for better user interface, I tried to make it in WPF.
I use TreeView and other controls for it in both platforms (Winforms and WPF)
in Winforms I could do this correctly usingbelow code:
private void Folder_FileTreeView_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
{
Folder_FileTreeView.Nodes.Clear();//this is necessary to clean first page node, after get new folders
if(e.Node.Text=="Desktop")//also this code is necessary to compare node
{
//Do something
}
}
Also in WPF I can get text of Item by below code:
private void Folder_FileTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (e.NewValue!=null)
{
StackPanel CustomStackPanel = (StackPanel)((TreeViewItem)e.NewValue).Header;
TextBlock textBlock = (TextBlock)CustomStackPanel.Children[1];
nodetext = textBlock.Text;//this line return text of item for compare
}
Folder_FileTreeView.Items.Clear();
}
If I don't use Folder_FileTreeView.Items.Clear() the above code return folders without clearing first page, but if I do use Folder_FileTreeView.Items.Clear() e.NewValue returns null.
Please help me to use together these codes: Folder_FileTreeView.Items.Clear();(or clear first page) and get text of selecteditem by user without return null
Thanks A lot
e.NewItem will be null if the TreeView used to have an item selected but now does not. When you clear the items, you are removing any selection, this of course changes the selection and raises the SelectedItemChanged event with null as the new selection- since there are no possible items that could be selected.
If you want to replace the items in the list with new items after the user makes a selection, the selected item will be null while that change is happening. You need to do the following:
Handle the SelectedItemChanged event and remember the new selected item in a variable.
For example, if they click on the item for "Desktop" set a variable (e.g. Path) to the path for the user's desktop (e.g. C:\Users\UserName\Desktop).
Clear the list of folders in the TreeView. This will trigger SelectedItemChanged again, but you want to ignore it this time because e.NewItem == null.
Read all the folders in Path and make new items for each of those folders.
The way was found by below code
private void Folder_FileTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
Folder_FileTreeView.SelectedItemChanged -= Folder_FileTreeView_SelectedItemChanged;
if (e.NewValue!=null)
{
StackPanel CustomStackPanel = (StackPanel)((TreeViewItem)e.NewValue).Header;
TextBlock textBlock = (TextBlock)CustomStackPanel.Children[1];
nodetext = textBlock.Text;//this line return text of item for compare
}
Folder_FileTreeView.Items.Clear();
Folder_FileTreeView.SelectedItemChanged += Folder_FileTreeView_SelectedItemChanged;
}
thank very much for every one helped me

Move selected index when typing in a WPF combobox

I have a problem with the combobox in WPF. You know that when you open the combobox and you start typing, that the selected index of the combobox is moving to the element that starts with the same letter. Well i actually need the same thing but a bit different.
The items in the combobox are actually binded to a class. This class has 2 properties, a Code property ( contains for example "XF15A") and a Description property ( contains for example "Radio"). I used a data template that actually binded the text for an combobox item to "[code] - [Description]".
Now when the type "XF" is goes to the combobox item that starts "XF". But what i now also need is that when you type "Ra" it should go to the combobox item "XF15A - Radio".
Do you guys know how to solve this? I'm also open for existing usercontrols.
Thanks,
My code is not quite what you want, but should give you an example of how you could do it yourself:
You got to handle PreviewTextInput yourself and let your algorithm decide which item to select. Here's a simple example:
XAML:
<ComboBox x:Name="cb" PreviewTextInput="ComboBox_PreviewTextInput">
<ComboBoxItem>adsfsf</ComboBoxItem>
<ComboBoxItem>adsfsf</ComboBoxItem>
<ComboBoxItem>acdd</ComboBoxItem>
<ComboBoxItem>adsfsf</ComboBoxItem>
</ComboBox>
Code Behind:
private void ComboBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
cb.IsDropDownOpen = true;
foreach (ComboBoxItem item in cb.Items)
{
var str = (string)item.Content;
if(str.Contains(e.Text))
{
cb.SelectedItem = item;
break;
}
}
}

Programmatically selecting an Item in a ListBox

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! :)

DataGridViewCombBoxColumn cell value and different dropdown list

I've a very trivial requirement which makes me go nuts. I've a DataGridView in windows forms application. This contains one databound ComboBox Column. I'm using DisplayMember and ValueMember properties of that combobox.
Now my requirement is ComboBox should show the list of DisplayMembers in drop down list but when user selects one item from it, I should display the part of that DisplayMember in the combobox cell visible to the user. For example.
My display member list looks as below:
"Cust1 - Customer 1"
"Cust2 - Customer 2"
"Cust3 - Customer 3"
and when user selects any one of them from the above list (Say user selected 'Cust2 - Customer 2') then I need to display the value in the combobox column cell as only "Cust2" instead of complete DisplayMember text.
This DisplayMember list is a combination of two fields from the datasource bound to it i.e. First part points to CustomerCode field and second part points Customer name. I need to display only CustomerCode in the ComboBox cell after user selects one item from the drop down list.
How can I do this? Or should I come up with my own control which will have a different AutoCompleteCustomSource and display member value. Even I'm confused with that approach too.
Update: As no one has come up with any solution to my problem. Now I'm starting a bounty for that, also if anyone can suggest me other way to implement the same functionality, it would be great.
I've even tried to come up with my own control and tried to work on simple combobox to display a different value than the selected dropdown list, even that didn't work. Is there any other way to implement this? Any tips and tricks are greatly appreciable.
#Anurag: Here is the code which I've used.
Created a datagridview in the design mode. Created one column of type 'DataGridViewComboBoxColumn' that and named it as CustomerColumn.
In the designer file it looks like below:
private System.Windows.Forms.DataGridViewComboBoxColumn CustomerColumn;
This is the entity class which I've used for datasource
public class Customer
{
public int Id { get; set; }
public string CustCode { get; set; }
public string CustName { get; set; }
public string NameWithCode { get; set; }// CustCode - CustName format
}
In the form load event I'm doing the following:
CustomerColumn.DataSource = GetCustomers();
CustomerColumn.DisplayMember = "NameWithCode";
CustomerColumn.ValueMember = "Id";
I'm answering my own question because I've implemented my own solution to this by using custom control.
This custom control is created by keeping a textbox above combo box in such a way that only drop down button of combobox is visible.
Now I've created a custom column in datagridview deriving the DataGridViewEditingControl from my usercontrol.
I've added a property in Usercontrol which will take drop down list source from the control which is hosting datagridview.
Now in the EditingControlShowing event I'm setting this property as below
private void dataGridView2_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if(dataGridView2.CurrentCell.ColumnIndex.Equals(0) && e.Control is UserControl1)
{
var uscontrol = e.Control as UserControl1;
uscontrol.DropDownListSource = source;
}
}
This drop down list source is used in the usercontrol to set the autocompletesource to the textbox and datasource to the combobox as below:
Whenever I set the DropDownDataSource I'm firing an event in the usercontrol which will do the following. This is to ensure that every time EditingControlShowing event occurs for this column in DataGridView, this source is updated for textbox and combobox in usercontrol.
private void DropDownSourceChanged(object sender, EventArgs eventArgs)
{
textBox1.AutoCompleteCustomSource = DropDownListSource;
textBox1.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
textBox1.AutoCompleteSource = AutoCompleteSource.CustomSource;
comboBox1.DataSource = DropDownListSource;
}
Now whenever user starts typing in the textbox autocomplete source will display dropdown list with 'NameWithCode' values and if user selects one of them then I'll set it to the Text propery overidden in my usercontrol which will be used for the cell value in the DataGridView. Now based on the Textbox text (which is NameWithCode) I can get the code part and set it to the text property.
If user uses combobox dropdown button to select the item then I'll get the combobox selected text and set it in the Textbox which is ultimately used by the cell for getting value.
This way I could achieve the solution I want.
#Homam, solution also works but when I change the ComboBox's DropDownStyle to allow the user to type the value in the combobox it behaves weirdly and not getting up to the mark solution for my requirement. Hence I used this solution.
I know that this is not perfect solution, but I looked for a better one and I didn't find, so I went to a workaround
I did the following:
when the user open the ComboBox, I change the DisplayMember to "NameWithCode"
when the user close it, I return it to "CustCode"
You can Access to the ComboBox control by DataGridView.EditingControlShowing event for the DataGridView.
The code:
private void dataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
var comboBox = e.Control as ComboBox;
comboBox.DropDown += (s1, e1) => comboBox.DisplayMember = "NameWithCode";
comboBox.DropDownClosed += (s2, e2) =>
{
// save the last selected item to return it after
// reassign the Display Member
var selectedItem = comboBox.SelectedItem;
comboBox.DisplayMember = "CustCode";
comboBox.SelectedItem = selectedItem;
};
}
Note: You have to start the DisplayMember with "CustCode"
Good luck!
Each time at the offensive of event dataGridView1_EditingControlShowing there is addition of new handlers for events comboBox.DropDown and comboBox.DropDownClosed. It results in the increase of number of these handlers and their repeated calls. This code decides this problem.
private void dataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
var comboBox = e.Control as ComboBox;
comboBox.DropDown += comboBox_DropDown;
comboBox.DropDownClosed += comboBox_DropDownClosed;
}
private void comboBox_DropDown(object sender, System.EventArgs e)
{
var comboBox = sender as ComboBox;
if(comboBox != null)
{
comboBox.DropDown -= comboBox_DropDown;
comboBox.DisplayMember = "NameWithCode";
}
}
private void comboBox_DropDownClosed(object sender, System.EventArgs e)
{
var comboBox = sender as ComboBox;
if(comboBox != null)
{
comboBox.DropDownClosed -= comboBox_DropDownClosed;
var selectedItem = comboBox.SelectedItem;
comboBox.DisplayMember = "CustCode";
comboBox.SelectedItem = selectedItem;
}
}

Categories

Resources