wpf access lisbox selected item if it isn't string - wpf

I have a listbox which displays Name property from an array of Movie objects
<ListBox Name="listBox1" SelectionChanged="listBox1_SelectionChanged">
<ItemsControl ItemsSource="{Binding}" >
<ItemsControl.ItemTemplate >
<DataTemplate >
<TextBlock Name="textBlock1" Text="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ListBox>
How can I access the text of the textBlock that's inside the ListBox in Code?
I must use the value of the Name property in my code

The selected item reported by the listbox exposes you the object that owns the Name property bound in the TextBlock. At this point the game is over.

When you do the above every textblock inside the itemscontrol has a name textblock1 that too with a scope limited to each item container.
If you want each of those textblocks individually, I usually do something like:
<TextBlock Text="{Binding Name}" Loaded="TextBlock_Loaded"/>
And in the code register those textboxes in whatever way you wish. A list probably,
List<TextBlock> TextBlockList = new List<TextBlock>();
private void TextBlock_Loaded(object sender, RoutedEventArgs e)
{
TextBlockList.Add((TextBlock)sender);
}
And for example, access the stuff as:
String FirstItem = TextBlockList.ElementAt(0).Text;

Related

Binding Text Property of child element of ComboBoxItem

I have a WPF ComboBox with a static list of people with an image and first name. I am trying to bind the selected FirstName to a db table. The way I am doing it now (obviously wrong) I am only binding the object and hence writing:
System.Windows.Controls.ComboBoxItem
to my db table.
How can I bind the FirstName from the selected ComboBoxItem from the TextBlock.Text property? Is there a way to do this purely in WPF?
<ComboBox Text="{Binding Path=FirstName}">
<ComboBoxItem>
<StackPanel Orientation="Horizontal" >
<Image Source="/Images/Alice.png" />
<TextBlock Text="Alice" />
</StackPanel>
</ComboBoxItem>
<ComboBoxItem>
<StackPanel Orientation="Horizontal">
<Image Source="/Images/Bob.png" />
<TextBlock Text="Bob" />
</StackPanel>
</ComboBoxItem>
</ComboBox>
I am saving the changes to the db table on a button click event
private void SaveAndClose_Click(object sender, RoutedEventArgs e)
{
bindingView = (BindingListCollectionView)myCollection.View;
bindingView.CommitEdit();
db.SubmitChanges();
}
Instead of hard-coding the comboboxitems, you should use a datatemplate. Then, you should use the SelectedValuePath to select the value based on the FirstName property in your items. Then you can bind to the textbox.
If you want to bind to the textbox in xaml directly, you'll need to name the element (x:Name="myTextBox"). Then, bind your combobox's SelectedValue like so: SelectedValue="{Binding ElementName="myTextBox", Path="Text"}".
In general, I don't think binding a combobox to a textbox is a very good idea.

wpf binding text to parent listbox's contents

I have a listBox whose items are to be shown in a textbox format, like so:-
<ListBox ItemsSource="{Binding movieList}" Name="innerList">
<ListBox.ItemTemplate >
<DataTemplate >
<TextBox Text="-------" TextChanged="TextBox_TextChanged_1"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
EDIT:
Sorry, movie list was an observablecollection (of Movie) instead of being (of String)
How do I get the textbox to show the contents of its ancestor (the innerList) ?
If you want to display the title of a movie in the TextBox, just use that:
<TextBox Text="{Binding Title}" TextChanged="TextBox_TextChanged_1"/>
(assuming the items in the list are objects with a Title property)
From Binding Declarations Overview
Optionally, a period (.) path can be used to bind to the current
source. For example, Text="{Binding}" is equivalent to Text="{Binding
Path=.}".
So following should do it.
<TextBox Text="{Binding}" TextChanged="TextBox_TextChanged_1"/>

Getting the SelectedItem from a combobox in a DataTemplate

Lets say I've got a DataTemplate like so
<DataTemplate x:Key="Body">
<StackPanel Orientation="Horizontal">
<ComboBox ItemsSource="{Binding Path=Person.Children}"></ComboBox>
<Button Click="Button_Click">Hello</Button>
</StackPanel>
</DataTemplate>
Which shows a list of ComboBoxes followed by a button.
Now, on clicking the button I need to discover the value in the combo next to the button pressed. I can get the data context as below but can't work out how to get the combos SelectedItem
private void Button_Click(object sender, RoutedEventArgs e)
{
// Can get the data context
var p = ((Button)sender).DataContext as Person;
// How to get the value in the combo ...?
}
you can also reference the combobox in your codebehind if you give it a name. However its cleaner to use a separate class to do your logic than the code behind. Such as a viewmodel.
then you could also do something like this...
<DataTemplate x:Key="Body">
<StackPanel Orientation="Horizontal">
<ComboBox ItemsSource="{Binding Path=Person.Children}"
SelectedItem="{Binding Path=SelectedChild}"
IsSynchronizedWithCurrentItem="True"/>
<Button Command="{Binding Path=ButtonCommand}">Hello</Button>
</StackPanel>
</DataTemplate>
Instead of using the Click event handler, use a Command and bind the CommandParameter property to the ComboBox.SelectedItem. Then in your command's executed logic, you can use the parameter.

Why is this WPF ComboBox not showing the selected value?

<CombobBox x:Name="cbo"
Style="{StaticResource ComboStyle1}"
DisplayMemberPath="NAME"
SelectedItem="{Binding Path=NAME}"
SelectedIndex="1">
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=NAME}"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
In the Window OnLoaded event, I wrote the code to set the ItemsSource:
cbo.ItemsSource = ser.GetCity().DefaultView;
While loading the window I can see that the initially the the first item is loading but at the same time it clears the displayed item. I am stuck in this scenario and any help is appreciated.
Regards
Kishore
QUICK ANSWER : Set SelectedIndex = 1 from code-behind.
It seems that the code in XAML executes first (the InitializeComponent() method), which sets SelectedIndex = 1, but ItemsSource is not specified yet! So SelectedIndex won't affect! (And remember, you cannot specify ItemsSource before InitializeComponent())
So you have to manually set SelectedIndex = 1 after setting ItemsSource.
You should do like this :
XAML
<ComboBox x:Name="cbo"
Style="{StaticResource ComboStyle1}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=NAME}"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Code
cbo.ItemsSource = ser.GetCity().DefaultView;
cbo.SelectedIndex = 1;
Or this:
XAML
<ComboBox x:Name="cbo" Initialized="cbo_Initialized"
Style="{StaticResource ComboStyle1}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=NAME}"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Code
private void cbo_Initialized(object sender, EventArgs e)
{
cbo.SelectedIndex = 1;
}
Also note that i've removed DisplayMemberPath="NAME" because you cannot set both DisplayMemberPath and ItemTemplate at the same time. And also, use either SelectedItem or SelectedIndex, not both.
Resetting the ItemsSource will mess up the selection.
Also, you are setting both SelectedItem and SelectedIndex. You want to set only one of these; if you set both, only one will take effect.
In addition, your SelectedItem declaration is probably wrong. SelectedItem="{Binding NAME}" will look for an item which is equal to the value of the NAME property of the ambient (probably Window-level) DataContext. This will work only if the ComboBox.ItemsSource is a list of strings. Since your ItemTemplate works, I assume ComboBox.ItemsSource is actually a list of City objects. But you are telling WPF that the SelectedItem should be a string (a NAME). This string will never be equal to any City object, so the result will be no selection.
So to fix the problem, after setting ItemsSource, set either SelectedItem or SelectedIndex, depending on your requirements and your data model:
cbo.ItemsSource = ser.GetCity().DefaultView;
cbo.SelectedIndex = 1;
// or: cbo.SelectedItem = "Wellington"; // if GetCity() returns strings - probably not
// or: cbo.SelectedItem = City.Wellington; // if GetCity() returns City objects

Silverlight: How to dynamically bind a ComboBox in a ListBox ItemTemplate?

I have a list box that requires at least one ComboBox. I couldn't find a way to place the ComboBox in the ItemTemplate I use.
...
<DataTemplate x:Key="parts_template">
<StackPanel Orientation="Horizontal">
<TextBlock .../>
<ComboBox .../>
</StackPanel>
</DataTemplate>
...
<ListBox x:Name="lb_parts" ItemTemplate="{StaticResource parts_template}" .../>
...
How do bind that ComoBox in the DataTemplate to an ObservableCollection in the code behind?
Another thing you could try is subscribe the Loaded event on the ComboBox.
Then you can set the ComboBox.ItemsSource in the EventHandler to MyObservableCollection.
Have a look
XAML:
<DataTemplate x:Key="parts_template">
<StackPanel Orientation="Horizontal">
<TextBlock .../>
<ComboBox Loaded="ComboBox_OnLoaded">
<!-- ComboBox ItemTemplate -->
</ComboBox>
</StackPanel>
</DataTemplate>
C# Code Behind:
private void ComboBox_OnLoaded(object sender, EventArgs e)
{
((ComboBox)sender).ItemsSource = MyObservableCollection;
}
Okay, here is how you can add a ComboBox to the ListBox in the code behind.
Create a ComboBox
ComboBox x = new ComboBox();
If you have a data source that populates the ComboBox then you can just bind that
x.ItemsSource = e.Result;
If you do not and want to manually add items to the ComboBox:
ComboBoxItem y = new ComboBoxItem();
Set the Content of the Item to what you want displayed in the ComboBox
y.Content = "Hello";
Now all that is left, is to add the ComboBoxItem to the ComboBox (only if you are creating the Items manually), and then the ComboBox to the ListBox
x.Items.Add(y);
//testing is my ListBox
testing.Items.Add(x);
You should be able to set the data context to the List itself
lb_Parts.DataContext=myCollection;
Then you should be able to bind to it in the template
<DataTemplate x:Key="parts_template">
<StackPanel Orientation="Horizontal">
<TextBlock .../>
<ComboBox ItemSource={Binding}/>
</StackPanel>
</DataTemplate>

Resources