Can't select items in ListBox when CanDrag=True - c#

I'm having trouble enabling drag (as in drag&drop) in an UWP ListBox. The selection stops working when I do that.
I have an UWP ListBox that contains an ItemTemplate with a single TextBlock in it. Everything was fine with the selection of items until I enabled CanDrag (i.e. drag&drop) on the TextBlock in the ListItem. After this I can't select items in the ListBox any longer by clicking on the items in the list. I can change selection by moving the focus with the arrow keys but selection with mouse interaction is no longer possible. If I set CanDrag back to False, selection starts working again.
Am I doing something wrong?
<ScrollViewer Grid.Column="0" HorizontalScrollMode="Disabled" VerticalScrollMode="Auto">
<ListBox x:Name="addProcessorListBox" ItemsSource="{Binding ProcessorTypes}"
SelectionMode="Single" DoubleTapped="OnDoubleTapped">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Padding" Value="0" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Margin="8,2,10,2" Text="{Binding Key}" FontSize="15" FontWeight="Bold"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate x:DataType="models:ProcessorType">
<TextBlock Grid.Column="0" Margin="18,8,10,8" Text="{Binding DisplayName}" FontSize="15" CanDrag="True" DragStarting="Processor_DragStarting"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
I tried changing the ListBox to a ListView, but the same behavior persists, i.e. selection does not work when clicking on the text.

I can reproduce this issue. I've reported it to the relevant team. They're investigating this issue.
As a workaround, you could use ListView control, but you do not need to drag the TextBlock in its ItemTemplate. You could choose to drag the whole ListViewItem by setting CanDragItems="True" and handling the DragItemsStarting event.
<ListView x:Name="addProcessorListBox" ItemsSource="{Binding ProcessorTypes}"
SelectionMode="Single" DoubleTapped="AddProcessorListBox_DoubleTapped" CanDragItems="True" DragItemsStarting="AddProcessorListBox_DragItemsStarting">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Padding" Value="0" />
</Style>
</ListView.ItemContainerStyle>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Margin="8,2,10,2" Text="{Binding Key}" FontSize="15" FontWeight="Bold" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Grid.Column="0" Margin="18,8,10,8" Text="{Binding DisplayName}" FontSize="15" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

We have confirmed that the best approach is ListView as we have it implemented in our github sample here
Actually the problem isn't quite related to ListBox/ListView but with
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
The following doc mentions that Stretch will stretches the child element to fill the allocated space of the parent element. But in this case, what is the size of parent space? Selection won't fail if specified Left/Right/Center but only with Stretch.
So actually this is a coding issue and you will need the property to set the size of parament element.

Related

How to force WPF textboxes contents to be displayed above other controls similar to excel cells

I have an ItemsControl that contains a textbox for each binding item and I want to allow overlaying text box content if its content is wider than the textbox width similar to excel cells overlaying behavior.
Is there a way to do this?
<ItemsControl ItemsSource="{Binding Path=MyCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Width="100"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding}" TextWrapping="WrapWithOverflow"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You can use tooltip for that. You just need to bind the source with itself.
<ListView ItemsSource="{Binding Path=MyStringCollection}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Width="100"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding}" TextWrapping="WrapWithOverflow" ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=Text}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
For further information:
DrawToolTip Event
Set ToolTipSize
To replicate a similar behavior, you can make use of a Popup.
To implement a similar behavior, you first must disable content wrapping of your TextBox.
Then replace the current TextBox with a TextBlock, which is used to display the text.
The Popup, which actually contains the editable TextBox, will then overlay this TextBlock at the exact position, thus hiding the TextBlock to make it appear to stretch and overlay the adjacent items.
A MultiTrigger will close the Popup as soon as the focus moved outside the ListBoxItem.
To improve performance you should use the VirtualizingStackPanel as items host.
<ListView ItemsSource="{Binding MyStringCollection}"
HorizontalAlignment="Left"
Width="800">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Border BorderThickness="1"
BorderBrush="Gray">
<TextBlock Text="{Binding}" />
</Border>
<Popup x:Name="EditableTextSiteHost"
PlacementTarget="{Binding ElementName=TextSite}"
Placement="Relative"
Height="{Binding ElementName=TextSite, Path=ActualHeight}"
AllowsTransparency="True"
FocusManager.FocusedElement="{Binding ElementName=EditableTextSite}">
<TextBox x:Name="EditableTextSite"
Text="{Binding TextData}" />
</Popup>
</Grid>
<DataTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=IsSelected}"
Value="True" />
<Condition Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=IsKeyboardFocusWithin}"
Value="True" />
</MultiDataTrigger.Conditions>
<Setter TargetName="EditableTextSiteHost"
Property="IsOpen"
Value="True" />
</MultiDataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<!-- Make items overlap -->
<Setter Property="Margin"
Value="-2,0,0,0" />
<Setter Property="Padding"
Value="0" />
<Setter Property="Width"
Value="50" />
<Style.Triggers>
<!-- Apply zero Margin on the first item -->
<DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}"
Value="{x:Null}">
<Setter Property="Margin"
Value="0,0,0,0" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>
To-do
This is just a raw example, a proof of concept. You would have to improve the behavior. For example, you would want to close the Popup when the user scrolls or moves the Window. Otherwise, since Popup itself is a Window, the Popup would not move to follow the placement target. You could move the related logic to an attached behavior.
You likely also want to improve the selection behavior. Currently the selection highlight border does not (virtually) extend to surround the Popup. You have to mimic this by applying a Border on the TextBox that will replicate the ListBoxItem highlight border.
I managed to produce the excel cells overlay behavior by using a Grid with dynamic column count using this helper dependency properties https://rachel53461.wordpress.com/2011/09/17/wpf-grids-rowcolumn-count-properties/ as a container template of ItemsControl and binding the column index of each textbox to the ordered item index and binding Grid.ZIndex to the reversed index to be displayed above the adjacent text boxes.
<ItemsControl ItemsSource="{Binding MyCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid HorizontalAlignment="Left" helpers:GridHelpers.ColumnCount="{Binding MyCollection.Count}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Column" Value="{Binding ItemIndex}"/>
<Setter Property="Grid.ZIndex" Value="{Binding ReversedIndex}" />
<Setter Property="Grid.ColumnSpan" Value="{Binding MaxMergedCells}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBox MinWidth="30" Text="{Binding }"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>

How to resize width of an image in a listview in WPF?

I have a ListView that contains Image as the Items. I want the width of each image to follow the width of the ListView whenever I resize the Grid that contains it.
<!--Playlists-->
<Grid Column="0">
<ListView Grid.Row="1" Grid.Column="1"
HorizontalAlignment="Stretch"
... >
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<!--Images-->
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type models:PlaylistModel}">
<Grid HorizontalAlignment="Stretch">
<Image Source="{Binding ImagePath}"
Stretch="Uniform">
</Image>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
<GridSplitter Grid.Column="0" />
Source: http://www.teixeira-soft.com/bluescreen/2016/03/21/c-how-to-make-a-panel-within-a-datatemplate-fill-the-entire-width-of-a-listview-or-itenscontrol-derivative/
This is what happens
As seen here, the width of the image doesn't resize at all. The image size just stays the same even when the size of the ListView changes. However, if I set the width of the Grid inside of DataTemplate then the Image would actually follow that width.
Looks like it was a mistake to use ListView. Changing everything to a ListBox fixed it for me.
Leaving this here if someone encounters the same problem.
<ListBox HorizontalAlignment="Stretch">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type models:PlaylistModel}">
<Image Source="{Binding ImagePath}"
Stretch="Uniform" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

How to align Text in DataTemplate choosen by a DataTemplateSelector?

I am trying to align text in a DataTemplate of a ListBox depending on the choice of the DataTemplateSelector.
What I want is something like this:
And tried to use a DataTemplateSelector
<DataTemplate x:Key="RequestTemplate" DataType="local:Message">
<TextBlock Text="{Binding Text}" Background="LightGreen" TextAlignment="Left" TextWrapping="Wrap"/>
</DataTemplate>
<DataTemplate x:Key="ResponseTemplate" DataType="local:Message" >
<TextBlock Text="{Binding Text}" Background="Yellow" TextAlignment="Right" TextWrapping="Wrap"/>
</DataTemplate>
<local:MesssageDataTemplateSelector x:Key="MessageDataTemplateSelector"
ResponseTemplate="{StaticResource ResponseTemplate}"
RequestTemplate="{StaticResource RequestTemplate}" />
The ListBox itself:
<ListBox ItemTemplateSelector="{StaticResource MessageDataTemplateSelector}" ItemsSource="{Binding Messages}" />
The colors are applied the alignment is not.
I also tried HorizontalAlignment, also not working. How to accomplish the effect?
One solution is to change the ListBoxItem style so that its HorizontalContentAlignment is Stretch:
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>

Scroll Images horizontally in ListBox when displaying only active

I have collection of Images and I need create something like carousel with bullets.
Currently I have 2 ListBoxes
<ListBox Name="lb" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="0" ScrollViewer.HorizontalScrollBarVisibility="Auto"
IsSynchronizedWithCurrentItem="True"
ItemsPanel="{StaticResource HorizontalItemsPanel}"
ItemsSource="{Binding Source={StaticResource CharacterCollectionView}}"
ItemContainerStyle="{StaticResource CharacterContainerStyle}">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding SelectedItem.Image, ElementName=lb1}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox BorderThickness="0" Height="20" VerticalAlignment="Top" IsSynchronizedWithCurrentItem="True" Background="#66000000" Grid.Row="1" Name="lb1" ItemsSource="{Binding Source={StaticResource CharacterCollectionView}}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Margin" Value="0" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="#FFFFFF"/>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border Background="#4CFFFFFF" Width="6" Height="6" CornerRadius="3"></Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
1st ListBox for Images, 2nd - for bullets to change image. If click on Bullets, images changes correctly (Under change I mean setting image as selected, cause only selected items is visible)
But I need to add functionality to slide Images also without using that bullets (when you can slide images by touch or by sliding horizontaly). Currectly this only work when all images is visible.
How to make sliding for images when only selected item is visible?

ListView.ItemContainerStyle IsSelected property does not seem to affect selection on WinRT

I was trying to use IsSelected set directly to true (w/o binding) during debugging of an issue (at the end I am trying to use binding, but have found that even w/o binding this does not work).
The following code works fine in WPF (all items selected) but does not work on WinRT (no item selected after execution).
Is this a bug/feature?
The following XAML will compile in a WPF window and in a WinRT page..
<ListView SelectionMode="Multiple" HorizontalAlignment="Stretch">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="True"/>
</Style>
</ListView.ItemContainerStyle>
<TextBox Width="200"/>
<TextBox Width="200"/>
<TextBox Width="200"/>
<TextBox Width="200"/>
<TextBox Width="200"/>
</ListView>
You can solve this problem using predefined datatemplate for listviewItem.Hope this helps
<ListView SelectionMode="Multiple">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<ListViewItem IsSelected="True" >
<TextBox Height="30" Width="200" ></TextBox>
</ListViewItem>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<TextBox />
<TextBox/>
<TextBox/>
<TextBox/>
<TextBox/>
</ListView>

Categories