Get Name of Selected ListBoxItem on Button Click - c#

I'm new to WPF/C#, and I'm trying to create a simple sql query application to get used to it. I have a listbox and a corresponding button in my XAML:
<ListBox Name="dbTables" Grid.Column="1" Grid.Row="2">
<ListBoxItem>Log</ListBoxItem>
<ListBoxItem>DownloadRequest</ListBoxItem>
<ListBoxItem>EmailRequest</ListBoxItem>
</ListBox>
<!-- View report button -->
<Button x:Name="myButton" Grid.Column="1" Grid.Row="3" Margin="0,10,0,0" Width="125" Height="25" HorizontalAlignment="Right" Click="Button_Click">View</Button>
and the corresponding C# function:
private void Button_Click(object sender, RoutedEventArgs e)
{
String curItem = dbTables.SelectedValue.ToString();
Console.WriteLine("CurItem = " + curItem);
Results resultsPage = new Results(curItem);
this.NavigationService.Navigate(resultsPage);
}
However, when it outputs the CurItem it has this value:
CurItem = System.Windows.Controls.ListBoxItem: Log
Which then throws an exception when I try to run a SQL Query. I'm trying to get it to just be
CurItem = Log
I've tried several different ways but I can't seem to just get the name of the selected value without the object definition attached.

SelectedItem returns the currently selected item in the list box. Since you're populating your list box with ListBoxItems, that's what it will return. (Note, by the way, that your list box automatically generates ListBoxItem containers for its items - if you look in the visual tree, you'll find that this ListBox contains ListBoxItems, each of which contains a ListBoxItem. SelectedItem contains the content of the generated ListBoxItem, which is to say the ListBoxItem you're creating in markup.)
SelectedValue returns the value of the property of SelectedItem that is specified by ListBox.SelectedValuePath. If no SelectedValuePath is given, it returns SelectedItem, so if you don't know about SelectedValuePath, it seems like the two are the same thing. But if you populate your list with, say, Person objects, and set SelectedValuePath to "Name", the SelectedValue will contain the selected person's name, not a reference to the Person object.
So in your example, you can make SelectedValue return the string by setting SelectedValuePath to "Content", which is the property of the ListBoxItem that contains the strings you're using.
You can do it another way by not explicitly creating ListBoxItems and just populating the ListBox with strings. You have to declare a namespace referencing mscorlib to do this, so that you can represent string objects in XAML, but once you do, the result's simple:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<DockPanel>
<ListBox DockPanel.Dock="Top" Margin="10" x:Name="test" SelectedValuePath="Length">
<sys:String>Log</sys:String>
<sys:String>DownloadRequest</sys:String>
<sys:String>EmailRequest</sys:String>
</ListBox>
<TextBlock DockPanel.Dock="Top" Margin="10" Text="{Binding ElementName=test, Path=SelectedItem}"/>
<TextBlock DockPanel.Dock="Top" Margin="10" Text="{Binding ElementName=test, Path=SelectedValue}"/>
</DockPanel>
</Page>

The Selected Value is a ListBoxItem, so you can cast the value to ListBoxItem, and then use the Content property:
ListBoxItem selItem = (ListBoxItem)dbTables.SelectedValue;
Console.WriteLine(selItem.Content);

String curItem = (dbTables.SelectedValue as ListBoxItem).Content.ToString();

Related

Binding label to selected listbox value

Relatively new to WPF and binding. I have a Listbox filled with values. When a user selects a certain value I want to display details of that value over several labels and a textbox. The current LINQ query that fills my listbox list gets the whole table, so the data is inside that list. How do I go around passing the details of the selected value inside of a label?
My current code for the listbox is :
<ListBox x:Name="LBController" Grid.Column="1" HorizontalAlignment="Left" Grid.RowSpan="6" Grid.Row="1"
ItemsSource ="{Binding AllControllers}" SelectedValue="{Binding SelectedControllerID}"
SelectedValuePath="Id" DisplayMemberPath="Name" >
</ListBox>
If a value inside of the listbox is selected, I would like its name to be displayed on a seperate label
<Label x:Name="lbl_controllername"
Content="Controller Naam" HorizontalAlignment="Left" VerticalAlignment="Top"
Grid.Row="1" Grid.Column="2" FontFamily="Corsiva" FontSize="11" Margin="40,0,0,0"/>
EDIT : Thanks for the answers everyone. This does however seem to prove difficult when doing the same thing with a control that has a function behind it.
<TextBox x:Name="txt_CodeDetail"
TextWrapping="Wrap"
AcceptsReturn="True"
FontFamily="Corsiva"
FontSize="11"
Text="{Binding ControllerCode, Mode=TwoWay}"/>
For example I have a textbox, the text inside of it is converted into a string for a function the app does. This string is called ControllerCode. This was done by copy-pasting the code before but I want the textbox to be filled with a selected property from the value inside the listbox.
I can't use
Text="{Binding SelectedItem.Property Elementname=LBController}"
as that would get rid of Controllercode and ruin the function. How can I bind the textbox text to the selecteditem as well as maintain the string that is formed with controllercode?
If you need to display several properties of an element in some area of the window, then it is easier in this area to set a panel in which the data context is bound to the selected element.
And inside this panel, set a set of elements to represent the properties of the selected element.
Example:
<StackPanel DataContext="{Binding SelectedItem, ElementName=LBController}">
<TextBlock Text="{Binding FirstProperty}"/>
<TextBlock Text="{Binding SecondProperty}"/>
<!--Other elements-->
</StackPanel>

WPF ComboBox bind text to selected item

I try to bind a ComboBox to a collection:
<ComboBox Margin="4 0 2 0"
ItemsSource="{Binding YAxes}"
SelectedItem="{Binding SelectedYAxis, Mode=TwoWay}"
DisplayMemberPath="AxisTitle"
SelectedValuePath="AxisTitle"/>
Everything is fine, except Text of this ComboBox. On selection of item, the setter on SelectedYAxis fires and notifies, that property has been changed:
private IAxis _selectedYAxis;
public IAxis SelectedYAxis
{
get => _selectedYAxis;
set
{
_selectedYAxis = value;
OnPropertyChanged(nameof(SelectedYAxis));
}
}
but the text on ComboBox never changes to the selected items AxisTitle. How to display an AxisTitle of SelectedItem as a text of ComboBox?
UPD: Text is never shown, even if it's set explicitly:
<ComboBox Margin="4 0 2 0"
ItemsSource="{Binding XAxes}"
SelectedItem="{Binding SelectedXAxis, Mode=TwoWay}"
DisplayMemberPath="AxisTitle"
Text="Asdasd"/>
It doesn't set the text of ComboBox to "Asdasd".
UPD 2: I've changed the things to use DataTemplate, but this didn't work as well:
<ComboBox Margin="4 0 2 0"
ItemsSource="{Binding YAxes}"
SelectedItem="{Binding SelectedYAxis, Mode=TwoWay}"
ItemTemplate="{StaticResource AxisCBTextTemplate}"/>
And the resource section above:
<DataTemplate x:Key="AxisCBTextTemplate">
<TextBlock Text="{Binding AxisTitle}"/>
</DataTemplate>
UPD 3
An illustration to what do I mean:
The task of displaying some selected text should be trivial, but it has difficulties.
I've found the root cause of this issue. Each IAxis (it is a SciChart axis object) from XAxes and YAxes is already dispayed on the graph (i.e. bound). Binding them to other controls (like ListBox) causes an exception: "Must disconnect specified child from current parent Visual before attaching to new parent Visual.", I found it out while trying to bind them to ListBox.
Seemes like ComboBox catches such exceptions and doesn't output StackTrace for any case. In my case this exception was wrapped into NullReferenceException and occurred only on click on a ComboBox, that has no ItemTemplate set. Though I may not be fully correct in details, replacing XAxes and YAxes with collections of strings solves this issue.

selectedItem is not working in xaml

i am trying to set selected item through following code but its not working:
<StackPanel Orientation="Horizontal">
<TextBlock Text="Sort by" Margin="10" VerticalAlignment="Center"/>
<ComboBox Width="{StaticResource ComboWidth}" x:Name="sortcombo" ItemsSource="{Binding Path=SortOrder}" SelectionChanged="SearchCombo_SelectionChanged" SelectedItem="{Binding Path=DefaultSortIndex}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Sort}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
however it works fine if i use selectedIndex instead with binding to 0th index. Any thing wrong with declaration?
By the name of your property DefaultSortIndex maybe you are trying to bind an int for SelectedItem.
SeletedItem refers to an element of your collection binded to ItemsSource, so the property binded to SelectedItem must be of type of your collection elements.
If you bind int value to selected item then it will not work, you should bind element for that. For int value you can set it as mentioned in following post :
Set Selected Item of WPF Combobox to User Setting
found out the issue, actually the data source was creating new list everytime I call getData().

Bind ObservableCollection<XmlNode> to combobox wpf

I'm trying to bind a combobox to a ObservableCollection.When the form is displayed the combobox is empty.The same code with ObservableCollection of type string works perfectly. I've got a feeling that my XPath is wrong. Any suggestions are welcome:
XAML:
<ComboBox ItemsSource="{Binding ItemParameters, XPath=InnerXml/name,Mode=TwoWay}" SelectedIndex="0" Margin="2" VerticalAlignment="Top" HorizontalContentAlignment="Stretch" Grid.Row="1" Grid.Column="1" Height="24" />
ObservableCollection XmlNode :
public ObservableCollection<XmlNode> _itemParameters = new ObservableCollection<XmlNode>();
public ObservableCollection<XmlNode> ItemParameters
{
get { return _itemParameters; }
set { _itemParameters = value; }
}
The combobox should display the name attribute of each XmlNode in the collection:
Update:
I've tried using DisplayMemberPath in two different ways, but the combobox still contains no data:
DisplayMemberPath="{Binding XPath=name}" ItemsSource="{Binding ItemParameters}"
DisplayMemberPath="{Binding XPath=InnerXml/name}" ItemsSource="{Binding ItemParameters}"
Solution:
This did the trick, hope it helps someone else as well:
<ComboBox DisplayMemberPath="#name" ItemsSource="{Binding ItemParameters}"
First of all you are setting Path and XPath at the same time, which are conficting properties, secondly you bind the ItemsSource, which has nothing to do with what you want to show inside the item. Either use DisplayMemberPath or an ItemTemplate for that, the ItemsSource should just be bound to ItemParameters.

Control which field is displayed in the textbox part of a databound WPF ComboBox

I have a ComboBox in WPF which is databound, and has data template which controls how each of the items is displayed. I have made it so that each item is displayed with two bits of text (for the Name and Path properties) and one image (for the Icon property).
At the moment when I select an item from the ComboBox the textbox bit of the ComboBox just changes to say "TestWPF.Result" which is the name of the class which I have populated the ComboBox with.
I'm interested in one (or both) of two things:
How do I change it so that it displays the value of one of the fields there (eg. so it shows the value of the Name field rather than the name of the class)?
Is it possible get it to use the same DataTemplate there as in the list of items, so that once I have selected an item it displays in the closed ComboBox the same way as it looks in the list of items. Basically I've got a DataTemplate called ShowResults and a ComboBox which uses that template. I've also added in a separate ContentControl which I've got to show the details of the selected item in the ComboBox, but I want to get that to replace the textbox in the ComboBox.
Update:
Thanks for the first answer. I've tried using a separate ContentControl, as you've described, and it works fine. The question now is how to replace the textbox part of the ComboBox with this ContentControl. Any hints on that would be most welcome.
Also, is it possible to replace the textbox bit of the ComboBox control with a mixture of the ContentControl and a textbox, so that I can still type in the textbox to help select items from the ComboBox, but then when I close the dropdown the rest ContentControl bit will be populated with the rest of the text and the icon. Hope that makes sense - ask questions if it doesn't!
Code:
I've been asked to post my code - so here it is. I've tried to remove things that I know are definitely not relevant, but I'm not sure exactly what is relevant so when in doubt I've left things in.
<Window x:Class="TestWPF.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:custom="clr-namespace:TestWPF"
Title="Window1" Height="300" Width="843" Loaded="Window_Loaded">
<Window.Resources>
<DataTemplate x:Key="ShowResult" DataType="TestWPF.Result">
<StackPanel Margin="5" Orientation="Horizontal">
<Image Width="32" Height="32" Source="{Binding Path=Image}"/>
<StackPanel Margin="5">
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}"/>
<TextBlock Text="{Binding Path=Path}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid Width="786">
<Button Height="23" HorizontalAlignment="Right" Margin="0,24,166,0" Name="btnTest" VerticalAlignment="Top" Width="75" Click="btnTest_Click">Add</Button>
<ComboBox StaysOpenOnEdit="True" DropDownClosed="comboBox1_DropDownClosed" PreviewTextInput="comboBox1_PreviewTextInput" SelectionChanged="comboBox1_SelectionChanged" ItemTemplate="{StaticResource ShowResult}" Margin="259,109,22,89" Name="comboBox1" IsEditable="True" />
<ContentControl Height="50" Margin="268,0,22,21" Name="contentControl1" VerticalAlignment="Bottom" Content="{Binding ElementName=comboBox1,Path=SelectedValue}" ContentTemplate="{StaticResource ShowResult}"/>
</Grid>
You got the binding part right - binding to the data and using a DataTemplate to display the source the way you want to.
As to your second question, a way to do it would be to use a ComboBox with IsEditable="True" as you have, and withing the TextChanged event handler check if the comboBox.Items contains the new value, if not check use Linq to seach for a match:
if (comboBox.Items.Contains(e.NewValue))
return;
var matches =
with comboBox.Items
select item
where item.BeginsWith(e.NewValue);
if (matches.Count > 0)
comboBox.SelectedItem = matches.First();
Just place the Property Binding expression to the textBox,You dont need to apply template.
Another way to get exact Data template, Place a ContentControl in the place of textBox and assign the same DataTemplate (say x:Name="robinTemplate")
<ContentControl Content="{Binding ElementName=cmbBox,Path=SelectedValue}" ContentTemplate="{StaticResource robinTemplate}"/>
For making the Selected content display in the same way :
Create a copy of the combobox control template and you will find a ContentPresenter there. Replace that with the ContentControl.. This is not the right solution though.

Categories