How to disable automatic selection of the selected item in ComboBox - c#

I have a combobox which works as directory selector. Visually its items are checkboxes, each checkbox is directory. User can check any of the checkboxes and this way make a selection of 2, 3, 10, you name it, directories.
This is the combobox binding:
<ComboBox ItemsSource="{Binding Path=KnownDirectories}"
IsEditable="True" IsReadOnly="True" Text="{Binding Path=WorkingDirectory}">
It works.
What does not work is a case when user clicks not at the chekbox rectangle, but somewhere else, so it is the case when user actually selects the row, not switches the checkbox. In this case WPF selects the row, and sets its ToString representation (which is name of the type in this case) as WorkingDirectory.
As the effect, instead of something like "C:\my_dir" I see "DirectoryType".
How to disable this automatic selection when user selects (clicks) entire row instead of clicking on checkbox toggle?
Temporarily I simply overrode ToString in my DirectoryType.
Initial item template for combobox:
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Path=IsDirectorySelected}">
<Label Content="{Binding Path=DirectoryName}" />
</CheckBox>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
After Ash suggestion (all errors are mine):
<DataTemplate>
<ComboBoxItem IsSelected="{Binding Path=IsDirectorySelected}">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ComboBoxItem}},Path=IsSelected}">
<Label Content="{Binding Path=DirectoryName}" />
</CheckBox>
</StackPanel>
</ComboBoxItem>
</DataTemplate>

Related

DataGrid ComboBox has no selected item when clicked the first time

Recently I asked similar questions here and here, but could not fix the issue properly.
I have a DataGrid with ComboBox that can contain either a selected item or not. But if it does then the ComboBox should select it when the dropdown is opening which is doesn't.
Currently I have this code which works except when opening the dropdown the first time. It is nothing selected.
<DataGridTemplateColumn Header="Company">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=DataContext.Companies}"
SelectedItem="{Binding Company, Converter={StaticResource NullValueConverter}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Company, Converter={StaticResource NullValueConverter}}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
The NullValueConverter prevents exceptions if the Company is null.
If your company was not a string as you mentioned in the comments then it can't display the Name unless you set
DisplayMemberPath="Name" or create an ItemTemplate.
You should use SelectedItem="{Binding
Company,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" to update
the value as soon as it changes because if you don't it will only
raise ProperyChanged when you focus another cell or row.
if your Property was immutable or a value type then you
should use SelectedValue="{Binding Path=Company,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" SelectedValuePath="Content"
.

WPF Combobox property IsTextSearchEnabled - how to not allow own text

I have a Combobox in a DataGrid which allows IsTextSearchEnabled. This works but the user is allowed to put their own text when the item is not found in the combobox. Is there a property that will stop this, or what can I do to stop the user adding their own text?
The xaml
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding DataContext.Types,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=Window}}"
x:Name="cmbDeploymentEditType"
SelectedItem="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedValue="Type"
Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsTextSearchEnabled="True"
IsSynchronizedWithCurrentItem="False"
IsEditable="True">
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
Thanks
There are multiple ways you can handle this, you can use a control that stops this like the XamMultiColumnComboEditor with CustomValueEnteredAction setting. Or you could do validation to enforce the rule you want.

LostFocus event firing upon getting Focus

I have an itemscontrol that is bound to a collection of objects.
in the data template, i bind an action that is to be used by all of the controls created if their focus is lost.
In the control, there is a textbox so if there are 1 items in the item controls ItemSource, there will be 2 textboxes.
Now, if Textbox 1 has focus and I click somewhere besides Textbox 2, the action is executed once (because the focus was lost). But if I click in Textbox 2, the action is executed twice. Why?
<ItemsControl Grid.Row="1" Margin="0,5,0,5" ItemsSource="{Binding
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}, Path=Collection}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type ct:CollectionItem}">
<cc:TestControl
ValueChangedAction="{Binding
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}, Path=ValueChangedAction}"
VerticalAlignment="Center" HorizontalAlignment="Center" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This is the Control.
<ewt:DecimalUpDown Tag="{Binding Uid}" Grid.Row="0" Grid.Column="3"
HorizontalAlignment="Stretch" TextAlignment="Left" Margin="10,5,10,5"
FormatString="C2" ShowButtonSpinner="False" VerticalAlignment="Center"
Value="{Binding Value}" LostFocus="DecimalUpDown_LostFocus" />
The bound action is executed in this event handler.
If your action is supposed to update the source of the binding (e.g. the Window, it looks like from your example), you might want to try adding OneWayToSource to your Binding so that binding only occurs one way—from the textbox to whatever it's bound to.

WPF ListBox selection

I have a problem with extended selection in ListBox. Let's say I have a ListBox with 10 items and I'm selecting first 5 of them using Shift button. The SelectionChanged event is fired with 5 items. After that I want to select 3 items from those 5, again with Shift button pressed, but SelectionChanged event is not fired. How can I react to the second selection of items, when I'm selecting 3 of those 5 previously selected ones?
can you show the xaml code as well I would like to see what your binding looks like
it should looks something like this.. but I can't be certain unless I see your code
In Command binding you have used binding which has relative source binding...
consider making these changes in binding
1) using list box as Ancestortype
2) While binding use Path=DataContext.SelectionChangedCommand otherwise it will take list box as datacontext.
<catel:EventToCommand Command="{Binding Path=DataContext.SelectionChangedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}" DisableAssociatedObjectOnCannotExecute="False" PassEventArgsToCommand="True" />
here is an example of what the XAML would look like for ListBoxItem Template
<Grid>
<StackPanel Orientation="Horizontal">
<Label Width="180">Field1</Label>
<ListBox Height="200"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding List1, Mode=OneWay}"
Name="listBox1"
SelectionMode="Single"
Width="300">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Width="290">
<TextBlock Width="90" Text="{Binding}"></TextBlock>
<ComboBox Width="180" ItemsSource="{Binding DataContext.List2, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" DisplayMemberPath="Field1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<catel:EventToCommand Command="{Binding Path=DataContext.SelectionChangedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}" DisableAssociatedObjectOnCannotExecute="False" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>

XAML layout ItemsControl

I have searched extensively on Google and am struggling to find an easy example to follow for an ItemsControl which I think I need to be able to do the following.
I currently have a Grid with a scrollable Listbox containing Checkboxes which works as expected using the following XAML layout
<Grid>
<ListBox ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding Selections}" Margin="12,22,12,94">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked}"
Content="{Binding Path=Item.SelectionName}">
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
I now want to add a TextBox to the right of each Checkbox so it's aligned horizontally with 1 Checkbox and 1 Textbox per row. I thought I would have to use an ItemsControl to allow two controls but using the ItemsControl as below I lose the ability to scroll
<Grid>
<ItemsControl ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding Selections}" Margin="12,22,12,94">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked}"
Content="{Binding Path=Item.SelectionName}">
</CheckBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Also, if I try and add a textbox similar to
<DataTemplate>
<CheckBox IsChecked="{Binding sChecked}" Content="{Binding Path=Item.BookieName}" />
<TextBox />
</DataTemplate>
I get an error The object 'DataTemplate' already has a child and cannot add 'TextBox'
Essentially, I want it to look like this
Can anyone give me a few pointers on how to structure the controls in XAML to get my desired layout?
Just use a StackPanel in your DataTemplate and set the orientation to horizontal.
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding sChecked}" Content="{Binding Path=Item.BookieName}" />
<TextBox />
</StackPanel>
</DataTemplate>

Categories