ListView SelectionChanged won't update when enclosed TextBox clicked - wpf

I have a list view with a gridview. The gridview second column contains textboxes (and in case this is relevant to this particular problem, the textboxes are rendered by a datatemplate).
I want the listview SelectedItem to update when the user clicks in the textbox to type and reflect the row (or listview item) containing the textbox. Right now listview SelectedItem will update only if the user's click on a row is just outside the textbox. If I click the textbox or type in it, the highlighted row stays the same and no SelectionChanged occurs for the listview.
How can I get the listview's selecteditem to update? Can I maybe force a change in its selecteditem or enable the listview to see the textbox click as its own somehow?
Thanks in advance.
P.s. Solution located here:
https://drive.google.com/file/d/0B89vOvsI7UbdTmN5RVdLVTFGeXM/view?usp=sharing
ListView xaml:
<ListView x:Name="CombinedlistView" Grid.Column="0"
DataContext="{Binding ElementName=mainWindow}"
SelectedIndex="{Binding Path=SelectedIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView >
<GridViewColumn CellTemplate="{StaticResource labelTemplate}" />
<GridViewColumn CellTemplateSelector="{StaticResource fieldValueTemplateSelector}" />
</GridView>
</ListView.View>
</ListView>
TemplateSelector:
<loc:FieldValueTemplateSelector x:Key="fieldValueTemplateSelector"
StringTemplate="{StaticResource stringTemplate}"
DateTimeTemplate="{StaticResource dateTimeTemplate}"/>
DataTemplate where textbox is located:
<DataTemplate x:Key="stringTemplate" DataType="{x:Type System:String}">
<StackPanel Style="{StaticResource dataTemplateStackPanelStyle}" Name="stringTemplStack">
<TextBox Name="searchValText" Width="120"
Text="{Binding Path=TextVal, Mode=OneWayToSource}"
DataContext="{Binding ElementName=mainWindow}"/>
</StackPanel>
</DataTemplate>

try wiring up this event to your PreviewGotKeyboardFocus event on your listviewitem:
protected void SelectCurrentItem(object sender, KeyboardFocusChangedEventArgs e)
{
ListViewItem item = (ListViewItem)sender;
item.IsSelected = true;
}

Related

WPF Display ListView in tabs of TabControl with different content

I am trying to display a WPF ListView in a tab of TabControl. I am trying to achieve the following: if I click on a button, a new TabItem should be created and in that TabItem a ListView should be shown with its own content.
So if I click on another button, a new tab item should be created and the ListView in this second tab item should display another content.
I am setting the DataContext to display items in the list view. The lines in the list view are displayed like this:
XAML:
<GridViewColumn Width="1500">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding myLine}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
The listview is displayed like this:
<TabControl x:Name="tabControl" Grid.Column="2" HorizontalAlignment="Left" Height="372" Margin="10,32,0,0" VerticalAlignment="Top" Width="894">
<TabControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:MyTab}">
<TextBlock Text="{Binding _header}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type local:MyTab}">
<ListView x:Name="myListView" ...></ListView>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
How can I display various tabs with their own content?
You will have to bind your list of tabs from your DataContext to TabControl.ItemsSource.
<TabControl ItemsSource="{Binding Tabs}"/>
And on your DataContext have a property called Tabs that is a list or collection of your datatypes;
public IList<MyTab> Tabs { get; private set; }

Get ListView control values in combobox selection changed Event

I am adding Label and Combo box dynamically to ListView control in combo box Selection Changed Event.
I want to get label content for the selected list view Item
You can use VisualTreeHelper to navigate Label from the SelectedItem;
or
Simple Way, you can do like below(but do add null checks where ever necessary);
XAML Code:
<StackPanel>
<ListView SelectionChanged="Selector_OnSelectionChanged">
<ListViewItem>
<StackPanel>
<Label Content="Label1"/>
<ComboBox>
<ComboBoxItem>1</ComboBoxItem>
<ComboBoxItem>2</ComboBoxItem>
</ComboBox>
</StackPanel>
</ListViewItem>
<ListViewItem>
<StackPanel>
<Label Content="Label2"/>
<ComboBox>
<ComboBoxItem>1</ComboBoxItem>
<ComboBoxItem>2</ComboBoxItem>
</ComboBox>
</StackPanel>
</ListViewItem>
</ListView>
<TextBlock x:Name="TextBlock1" FontSize="25"/>
</StackPanel>
C# Code:
private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
string content =
((((e.AddedItems[0] as ListViewItem).Content) as StackPanel).Children[0] as
Label).Content.ToString();
TextBlock1.Text = "Selected Item's Label content is :" + content;
}
For simple solution, I have navigated programmatically;
((((e.AddedItems[0] as ListViewItem).Content) as StackPanel).Children[0] as Label).Content

WPF binding to CurrentItem

I have a WPF model which contains a viewsource, a listview, and a button, which is meant to execute an ICommand in the viewmodel for the item selected in the listview.
<Window.Resources>
<CollectionViewSource x:Key="teachingSessionsViewSource" d:DesignSource="{d:DesignInstance {x:Type local:TeachingSessionListItem}, CreateList=True}"/>
</Window.Resources>
...
<GroupBox Header="All Sessions"
DataContext="{Binding Source={StaticResource teachingSessionsViewSource}}">
<StackPanel>
<ListView x:Name="TeachingSessionList"
ItemsSource="{Binding}"
SelectedItem="{Binding Path=/}">
<ListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource noHeaderStyle}">
<GridViewColumn DisplayMemberBinding="{Binding SessionDate}"/>
<GridViewColumn DisplayMemberBinding="{Binding PresenterInitials}" Width="30" />
</GridView>
</ListView.View>
</ListView>
<Button Content="Un-Assign" Margin="5,5" Command="{Binding Path=/UnAssignPresentation}"
</StackPanel>
</GroupBox>
The problem is that the ICommand UnAssignPresentation is always executed on the first item in the list, regardless of which item is selected in the listview. That is to say, the currentItem property of the CollectionViewSource does not seem to be bound to the ListView.
What am I doing wrong? Thank you very much.
Try adding IsSynchronizedWithCurrentItem="True" to your ListView.
Also, prefer binding listview to a collection in your view model and not to a resource.
You can then add a property to the view model for the selected item
and bind the listview's selected item to that property in the view model
and either bind the button's command to a command in the view model that acts on the current item,or pass the item you want to act on via the command parameter binded to the selected item.

How can I access information in the selected row of a XAML gridview?

I have a listview with a gridview inside it and it is bound to a list of custom objects. In one cell I have three elements that I swap between, one of which is a hyperlink with a click event.
How do I get access to the 'CompanyName' that is bound in the same row when I go to the click event on the hyperlink?
This question may bely my ASP.Net background - I am very new to WPF.
<GridViewColumn Header="File" Width="100" DisplayMemberBinding="{Binding Path=CompanyFile}"/>
<GridViewColumn Header="Action" Width="300">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Status}" Visibility="{Binding Path=StatusVisibility}"></TextBlock>
<TextBlock Visibility="{Binding Path=ButtonVisibility}"><Hyperlink Click="Hyperlink_Click"><TextBlock Text="{Binding Path=Button}"></TextBlock></Hyperlink></TextBlock>
<ProgressBar Value="{Binding Path=Progress}" Visibility="{Binding Path=ProgressVisibility}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
The Hyperlink inherits the DataContext of the parent ListViewItem, so you just need to cast it:
void Hyperlink_Click(object sender, EventArgs e)
{
Hyperlink link = (Hyperlink)sender;
MyCustomObject obj = (MyCustomObject)link.DataContext;
string companyName = obj.CompanyName;
...
}
Another option is to bind the hyperlink's Command property to a command on your DataContext, rather than handling the Click event explicitly. This helps decoupling the view from the business-related code, and it's the usual way of doing things in the MVVM pattern.

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