Bind focus to datacontext in WPF - 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>

Related

Triggers override binding

Why is it that the binding Marked stops working when the triggers are used? Is there some way to fix this?
The multi selection ListBox has ListBoxItems with CheckBoxes, and the checkbox in an item is ticked when the corresponding item is selected, using mouse or keyboard or touch or whatever. The point with this demo is to not tick the checkboxes directly, but just multiselect the items and see the checkboxes get ticked as a consequence of that. This synchronization in the XAML works well, but since the Marked binding isn't working, the model won't get updated.
If I remove the triggers, then the binding Marked starts working. I know, because then the model gets updated when the checkboxes are ticked.
If I attach event handlers for Checked and Unchecked to the CheckBox, they fire even when the triggers are there.
<ListBox ItemsSource="{Binding Lines}" SelectionMode="Extended">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<CheckBox x:Name="cb"
Content="{Binding DisplayText}"
IsChecked="{Binding Marked, Mode=TwoWay}">
</CheckBox>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListBoxItem}}, Path=IsSelected}" Value="true">
<Setter TargetName="cb" Property="IsChecked" Value="true"/>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListBoxItem}}, Path=IsSelected}" Value="false">
<Setter TargetName="cb" Property="IsChecked" Value="false"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
EDIT:
Although the accepted solution below is good XAML, it crashes with Elmish.WPF, which I'm using. That's another issue, and will be solved through other forums.
The DataTriggers will obviously override the Binding, since the ListBoxItem's IsSelected property is always either true or false.
Replace the DataTriggers by an ItemContainerStyle:
<ListBox ItemsSource="{Binding Lines}" SelectionMode="Extended">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding DisplayText}"
IsChecked="{Binding Marked}"/>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding Marked}"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>

Listbox doesn't detect selected item

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.

Wpf Combobox selectedvalue trigger

I am trying to change the visibility with a trigger when a particular value in a combobox is selected, and I got the following XAML
<ItemsControl ItemsSource="{Binding AccessControl.Credentials}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid >
<ComboBox Name="chkFieldType"
SelectedValue="{Binding Path=ValueSourceType,Converter={StaticResource enumstringConv}}"
SelectedValuePath="Tag" SelectionChanged="chkFieldType_SelectionChanged" >
<ComboBoxItem Tag="User">User</ComboBoxItem>
<ComboBoxItem Tag="SessionCredential">Field</ComboBoxItem>
<ComboBoxItem Tag="Inherit">From other Resource</ComboBoxItem>
</ComboBox>
<Border " Visibility="Hidden">
<Border.Resources>
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=SelectedValue, ElementName=chkFieldType}" Value="Inherit">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Resources>
<ComboBox/>
</Border>
In this case a border. The selected value is "Inherit" of type string but the border remainds hidden.
I ran into the same problem and found that you have to set the visibility property using the style only. So instead of having the initial visibility set with:
<Border Visibility="Hidden">
You should set the initial visibility using the style:
<Style TargetType="....">
<Setter Property="Visibility" Value="Hidden"/>
<Style.Triggers>
....
</Style.Triggers>
</Style>
(I know it's kinda overdue but I thought maybe someone else might run into the same problem).
Try SelectedItem.Tag or SelectedItem.Content instead of SelectedValue
Set your binding on SelectedValue, not SelectedItem.SelectedValue. The way you currently have it, it is looking for ComboBoxItem.SelectedValue, which doesn't exist
<DataTrigger Value="Inherit"
Binding="{Binding Path=SelectedValue,
Converter={StaticResource enumstringConv},
ElementName=chkFieldType}">
I think it's because you are putting the DataTrigger in Border.Resources.
Try putting the style in the window.resources, with a x:key in order to apply the style to the border.
I think that the border.resources can not access to a control "outside it's own resources context"
SelectedItem and SelectedValue are two seperate properties on the ComboBox.
Since your ComboBoxItems are all strings you can change
<DataTrigger Binding="{Binding Path=SelectedItem.SelectedValue, ElementName=chkFieldType}" Value="Inherit">
to
<DataTrigger Binding="{Binding Path=SelectedItem, ElementName=chkFieldType}" Value="Inherit">
I ended up setting the visibility manually via the code behind when the selectedItem event is fired..

Databinding and Triggers compatability in WPF

I have a problem. I made a DataTemplate for a TreeView and I need to set the initial value of the ToggleButton's IsChecked property depending on my model. But it turns out that setting this property using triggers/setters disables the databinding.
Is it so? If yes, give me a suggestion how it can be fixed?
<DataTemplate x:Key="CellTemplate_Name">
<DockPanel x:Name="dock">
<ToggleButton x:Name="Expander"
IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource AncestorType={x:Type TreeViewItem}}}"> <--- Binding
...
<ToggleButton/>
...
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=ObjIsOpened, Converter={StaticResource DebugConverter}}" Value="true"> <--- Trigger
<Setter TargetName="Expander" Property="IsChecked" Value="true"></Setter>
</DataTrigger>
...
</DataTemplate.Triggers>
</DataTemplate>
Regards, Lerax.
First of all I suggest you read the excellent article by Josh Smith
Simplifying the WPF TreeView by Using the ViewModel Pattern
Based on that article, I would suggest defining a style for the TreeViewItem (using the ItemContainerStyle property of the TreeView) which binds its IsExpanded property to your model object's ObjIsOpened property. Then get rid of your trigger.
Example:
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded"
Value="{Binding ObjIsOpened, Converter={StaticResource DebugConverter}}"/>
</Style>
<DataTemplate x:Key="CellTemplate_Name">
<DockPanel x:Name="dock">
<ToggleButton x:Name="Expander"
IsChecked="{Binding Path=IsExpanded,
RelativeSource={RelativeSource
AncestorType={x:Type TreeViewItem}}}"> <--- Binding
...
<ToggleButton/>
...
</DataTemplate>
I suspect they do not disable data binding, they just have higher priority. Instead of using binding and trigger at the same time, why don't you use one of them (either binding or trigger)? E.g. you could bind to model directly, and don't use trigger at all...

ListBoxItem selection on TextBox focus

I have a ListBox showing items using the following DataTemplate:
<DataTemplate x:Key="PersonTemplate" DataType="{x:Type DAL:ResultItem}" >
<StackPanel Width="280" >
<TextBox BorderThickness="0" IsReadOnly="True" Background="Transparent" Text="{Binding FullName1, Mode=OneWay}"/>
...
</StackPanel>
</DataTemplate>
I am using a transparent, read-only, borderless TextBox as opposed to a TextBlock because I want users to be able to select the text for copying. Should I do it differently?
How can I write this so that when the user clicks on the TextBox, the ListBoxItem gets selected as well?
Thanks!
I found that the answer is just to do this from the ListBoxItem standpoint, adding the following to its DataTemplate:
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True"/>
</Trigger>
</Style.Triggers>

Resources