Listbox doesn't detect selected item - wpf

I have the following listbox:
<ListBox ItemsSource="{Binding AvailableTemplates}" Style="{DynamicResource SearchListBoxStyle}" SelectedItem="{Binding SelectedTemplate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate>
<RadioButton Content="{Binding}" GroupName="group" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
this doesn't detect as selected item changed if i select on the radiobutton. It only detects if i click under the radio button on the listbox row. Any ideeas how to amend to detect as selected item changed when clicking on the radio button?

If you only want to synchronize the RadioButton.IsChecked with ListBoxItem.IsSelected, you can use a binding
<RadioButton Content="{Binding}" GroupName="group"
IsChecked="{Binding Path=IsSelected, RelativeSource={
RelativeSource AncestorType={x:Type ListBoxItem}},Mode=TwoWay}"/>
If you don't want your items synchronized, you can use a Trigger that sets IsSelected whenever the item gets keyboard focus, although this will only keep an item selected as long as it has keyboard focus
<Style TargetType="ListBoxItem">
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
And if you want it selected regardless of if the element still has keyboard focus or not, you have to use a little code behind
<Style TargetType="{x:Type ListBoxItem}">
<EventSetter Event="PreviewGotKeyboardFocus" Handler="SelectCurrentItem"/>
</Style>
protected void SelectCurrentItem(object sender, KeyboardFocusChangedEventArgs e)
{
ListBoxItem item = (ListBoxItem)sender;
item.IsSelected = true;
}

You can not mistake: listBox.SelectedItem and radioButton.IsChecked
They are totally different things,
SelectedItem is called the ListBoxItem, your radiobutton is within a listboxitem.
You must make a binding for property IsChecked (RadioButton).

Try setting ListBoxItem.IsHitTestVisible to false (you may do this in xaml). It solved my selection problem elementary. My problem was that selection only worked when I clicked on white space in ListBox line but not a custom content.

Related

WPF IValueConverter for DataGrid.Cell Tooltip Visibility getting null Value in Convert

XAML for Converter
<ToolTip x:Key="toolTipGridCell" DataContext="{Binding Path=PlacementTarget,
RelativeSource={x:Static RelativeSource.Self}}"
Visibility="{Binding Path=PlacementTarget,
RelativeSource={x:Static RelativeSource.Self},
Converter={StaticResource ContentFitsVisibilityConverter}}">
<TextBlock FontWeight="Bold" Text="{Binding Path=Content.Text}"/>
</ToolTip>
....
<DataGrid ....>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="ToolTip" Value="{StaticResource toolTipGridCell}" />
</Style>
</DataGrid.CellStyle>
I need to either hide or show the tooltip on the cell bases on whether the content of that cell is fully visible given the cell's width.
When I remove the Visibility part of the ToolTip, I get the tool tip with cell contents - so the targeting seems to be correct.
But with the visibility defined as above, when the Convert function gets hit as I mouse over the cell, the first parameter (object value) is null, instead of being the DataGrid.Cell over which the tooltip is showing up.
In the Sample Code you have provided, both the datacontext and the visibility of the Tooltip control are bound to the same property "PlacementTarget". This caused the NullReferenceException. To Resolve this issue, bind datacontext and the visibility to the appropriate property in your viewmodel.

Conditionally changing the Foreground of a WPF ComboBox item depending upon a value in the databound ItemsSource item

I have a WPF ComboBox bound to a Collection List<Users>. I have applied a DataTemplate to show the FirstName using a TextBlock and this works as expected:
<ComboBox Margin="5" ItemsSource="{Binding Path=TheUsers}" Name="cboUsers">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Margin="10" Text="{Binding Path=FirstName}">
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>`
I have an item in my User class called IsActive which is a Boolean value. If true then I want to set the Foreground of the TextBlock to Navy.
I have spent so much time on what should be so easy and looked all over the web but most articles talk about changing the overall colour or binding to another element in the xaml.
I tried implementing a DataTrigger and after an hour removed the code because it was not working. It would not recognise my field name. Does anyone have a very simple guide to how to do this or what would be the best approach?
As you apparently are not dealing with fields after all, this style should do what you want:
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsActive}" Value="True">
<Setter Property="Foreground" Value="Navy"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
It would not recognise my field name.
You cannot bind to fields, end of story.

Bind focus to datacontext in WPF

I would like to bind the current focus to the datacontext. My menu system has a viewmodel that contains a list of ButtonViewModels as datacontext. How would I go about having the focused button be determined by the datacontext?
There is a FocusManager.FocusedElement, but this references to a control and the idea of a ViewModel is to not depend on the implementation of the View...
I tried to place a DataTrigger in the Button Style which binds to a property called IsFocused in the ButtonViewModel and in the Setter Bind FocusManager.FocusedElement to the Button where IsFocused is set to true. This should allow you to Control the Focus directly from the ButtonViewModel
<ItemsControl ItemsSource="{Binding ButtonViewModels}">
<ItemsControl.Resources>
<Style x:Key="FocusBindingStyle" TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding IsFocused}" Value="True">
<Setter Property="FocusManager.FocusedElement"
Value="{Binding RelativeSource={RelativeSource Self}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ItemsControl.Resources>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="Test" Style="{StaticResource FocusBindingStyle}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

WPF - Making selected listview column editable on button click

I have a listView with a gridview presentation and TextBlocks in each column. I would like to make the selected line editable by replacing the textblocks with TextBoxes and ComboBoxes when the user clicks on an edit button. I tried to do this by setting styles that toggles the visibility of the controls like this :
<Style x:Name="ItemDisplayStyle" TargetType="{x:Type TextBlock}" x:Key="ItemDisplayStyle">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Visibility" Value="{Binding Path=dislayMode}" />
</Style>
<Style x:Name="ItemEditStyle" TargetType="{x:Type FrameworkElement}" x:Key="ItemEditStyle">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Visibility" Value="{Binding Path=editMode}" />
</Style>
displayMode and editMode are Visibility properties set in the code-behind.
And lower in the xaml :
<GridViewColumn Header="Date de début" Width="80">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Margin="-6,0"
HorizontalAlignment="Stretch" TextAlignment="Center"
Text="{Binding Path=DateDebut, Mode=TwoWay}"
Style="{StaticResource ItemDisplayStyle}" />
<TextBox x:Name="tbDateDebut" Margin="-6,0"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"
Text="{Binding Path=DateDebut, Mode=TwoWay}"
Style="{StaticResource ItemEditStyle}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
My problem is that changing 'editMode' and 'displayMode' in the code-behind does not seem to be detected at the UI level.
Also, even if I get this to work, I don't have any idea of how to apply it only to the selected line.
I can do this separately by binding the visibility value with the ListView so that when the user selects a line, she/he gets the editable controls on that line but I really want to allow this only when they click on a button.
Have you Refreshed the contents of the Grid after making changes? You can use the Grid.GetColumn method and send the sender object i.e. edit button (which I suppose would be separate for each column) and then probably use the VisualTreeHelper to get the textbox and combobox in that column.
Also, why don't you use the 'IsReadOnly' property of the TextBox instead of replacing the TextBlock? Make it true or false as per your requirement.

Can a WPF ListBox be "read only"?

We have a scenario where we want to display a list of items and indicate which is the "current" item (with a little arrow marker or a changed background colour).
ItemsControl is no good to us, because we need the context of "SelectedItem". However, we want to move the selection programattically and not allow the user to change it.
Is there a simple way to make a ListBox non-interactive? We can fudge it by deliberately swallowing mouse and keyboard events, but am I missing some fundamental property (like setting "IsEnabled" to false without affecting its visual style) that gives us what we want?
Or ... is there another WPF control that's the best of both worlds - an ItemsControl with a SelectedItem property?
One option is to set ListBoxItem.IsEnabled to false:
<ListBox x:Name="_listBox">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsEnabled" Value="False"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
This ensures that the items are not selectable, but they may not render how you like. To fix this, you can play around with triggers and/or templates. For example:
<ListBox x:Name="_listBox">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
I had the same issue. I resolved it by leaving the IsEnabled set to true and handling the PreviewMouseDown event of the ListBox. In the handler set e.Handled to true in the case you don't want it to be edited.
private void lstSMTs_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
e.Handled = !editRights;
}
The magical incantation that will do the trick is:
<ListBox IsHitTestVisible="False">
Unfortunately, this will also prevent any scrollbars from working.
The fix to that is to put the listbox inside a scrollviewer:
<ScrollViewer>
<ListBox IsHitTestVisible="False">
</ListBox>
</ScrollViewer>
Is your ItemsControl/ListBox databound?
I'm just thinking you could make the Background Brush of each item bound to a property from the source data, or pass the property through a converter. Something like:
<ItemsControl DataContext="{Binding Source={StaticResource Things}}" ItemsSource="{Binding}" Margin="0">
<ItemsControl.Resources>
<local:SelectedConverter x:Key="conv"/>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<local:Control Background="{Binding Path=IsSelected, Converter={StaticResource conv}}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>

Resources