I'm trying to achieve a ToggleButton control template for listbox items. This is to be used in an application where the user can click on the listbox items to show a certain piece of functionality.
The listbox item template is defined as follows:
<Style x:Key="ExampleListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ToggleButton IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}"
HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch">
<StackPanel Orientation="Vertical">
<TextBlock x:Name="ExampleTitle" Grid.Row="0" Foreground="#333333"
FontFamily="pack://application:,,,/Resources/Fonts/#Neuropol Regular"
FontSize="16" Height="26" TextAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Top" Text="{Binding ExampleDisplayName}"
Margin="5"></TextBlock>
<TextBlock Grid.Row="1" Foreground="#333333" Margin="5,-5,5,3" HorizontalAlignment="Stretch"
TextAlignment="Left" FontFamily="Verdana" VerticalAlignment="Top"
TextWrapping="Wrap" Text="{Binding ExampleDescription}"/>
</StackPanel>
</ToggleButton>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and the listbox is defined as
<ListBox x:Name="_examplesListBox"
SelectionMode="Single"
BorderBrush="Transparent"
Background="Transparent"
ItemsSource="{Binding AllExamples}"
ItemContainerStyle="{StaticResource ExampleListBoxItemStyle}"
SelectedItem="{Binding SelectedExample, Mode=TwoWay}"/>
Here I have two textblocks, one bound to ExampleDisplayName, the other bound to ExampleDescription. The effect I am trying to achieve is to get the second textblock (description) to wrap around, constrained by the available space.
This is what I'm getting now:
What I'd like is for the second line showing example description to wrap based on the size of the listbox. When the application starts the listbox should auto-size to the first line + margin.
Any suggestions?
Removing that horizontal scrollbar should help with text wrapping:
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled">
I'm not quite sure how to auto-size ListBox on startup based on first text line size using only XAML.
Related
I have a WPF Datagrid defined like this in my XAML :
<DataGrid x:Name="DtgPoshResults" Style="{StaticResource DatagridResults}" ItemsSource="{Binding Path=PoshResults, UpdateSourceTrigger=PropertyChanged}" ClipboardCopyMode="{Binding ClipBoardCopyMode}" CellStyle="{StaticResource CenterDatagridCell}" SelectedValue="{Binding SelectedItemPoshResults, Mode=TwoWay}" ColumnHeaderStyle="{DynamicResource DataGridColumnHeaderStyle1}"/>
To get a textbox in each column header (in order to filter by column), I use a Template.
My Datagrid has a dynamic number of columns (that can vary each time I start a command) :
<Style x:Key="DataGridColumnHeaderStyle1" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<StackPanel Orientation="Vertical" Background="#FF444444">
<TextBlock x:Name="DtgResultsColumnName" VerticalAlignment="Center" Text="{TemplateBinding Content}" Foreground="White" Margin="5,5,5,0"/>
<StackPanel Orientation="Horizontal">
<TextBox Width="100" Margin="5" Text="{Binding DataContext.TextFilterColumn, RelativeSource={RelativeSource AncestorType=Window}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Margin="0,0,5,0" VerticalAlignment="Center">
<Hyperlink Foreground="White" Command="{Binding DataContext.FilterColumnName, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, UpdateSourceTrigger=PropertyChanged}" CommandParameter="{Binding ElementName=DtgResultsColumnName, Path=Text}">
Filter
</Hyperlink>
</TextBlock>
</StackPanel>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
After starting my command, the Datagrid displays results and looks like this :
When typing "lo" in the first textbox and clicking on "Filter", it works and I only get the line which is "localhost" but when the Datagrid is refreshed, all the textboxes are filled with the word "lo" :
I can't define a different Text Binding for each textbox as I have a dynamic number of columns so I don't know how to avoid that all textboxes in the headers get the same text when filter is applied.
Do you know how can I fix this?
Thanks and regards.
I have a XAML file which should make it possible to drag GridViewItems inside a GridView. Now I'm using an ItemSource for the GridView items and a DataTemplate to show them in the way I want them to be shown. That works. The following problem occured: Since I started using DataTemplate, the GridViewItems are not draggable. I can only drag the DataTemplate. That's weird, so the only part I can use to drag, is the area left and right of the GridViewItems because this is used for margin.
Why is the DataTemplate the 'draggable' control instead of the GridViewItem? I have tried numerous fixes but none seem to work out well.. I can ofcourse make it work without a DataTemplate, but it's much cleaner to use it like this.
<GridView Name="canvas" ItemsSource="{Binding GridviewItemList}" CanReorderItems="{Binding CanvasCanReorder}" CanDragItems="{Binding CanvasCanDrag}" ReorderMode="Enabled" AllowDrop="True" VerticalAlignment="Center" Width="660" Height="110" IsSwipeEnabled="False" ScrollViewer.VerticalScrollMode="Disabled" ScrollViewer.HorizontalScrollMode="Disabled">
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:MainPageItems">
<GridViewItem Name="{x:Bind GvName}" Margin="13 0 15 0">
<Border Width="100" Height="100" Background="{x:Bind BdBackground, Mode=OneWay}">
<TextBlock Height="60" Width="30" FontSize="40" Text="{x:Bind TbText, Mode=TwoWay}" Margin="{x:Bind TbMargin, Mode=TwoWay}"></TextBlock>
</Border>
</GridViewItem>
</DataTemplate>
</GridView.ItemTemplate>
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="DragItemsCompleted">
<core:InvokeCommandAction Command="{Binding CanvasDragCompleted}"></core:InvokeCommandAction>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</GridView>
Thanks in advance!
When you add GridViewItem in the DataTemplate, there are two ListViewItemPresenter in one GridViewItem. Please check it in the Live Visual Tree.
In UWP apps for Windows 10, both ListViewItem and GridViewItem use ListViewItemPresenter; the GridViewItemPresenter is deprecated and you should not use it. ListViewItem and GridViewItem set different property values on ListViewItemPresenter to achieve different default looks.
For more info, please refer Item containers and templates.
If you want to set Margin to the GridViewItem, we should be able to set the GridViewItem style in the GridView.ItemContainerStyle.
For example:
<GridView Name="canvas" ItemsSource="{Binding GridviewItemList}" CanReorderItems="{Binding CanvasCanReorder}" CanDragItems="{Binding CanvasCanDrag}" ReorderMode="Enabled" AllowDrop="True" VerticalAlignment="Center" Width="660" Height="110" IsSwipeEnabled="False" ScrollViewer.VerticalScrollMode="Disabled" ScrollViewer.HorizontalScrollMode="Disabled">
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:MainPageItems">
<Border Width="100" Height="100" Background="{x:Bind BdBackground, Mode=OneWay}">
<TextBlock Height="60" Width="30" FontSize="40" Text="{x:Bind TbText, Mode=TwoWay}" Margin="{x:Bind TbMargin, Mode=TwoWay}"></TextBlock>
</Border>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="Margin" Value="13 0 15 0"/>
</Style>
</GridView.ItemContainerStyle>
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="DragItemsCompleted">
<core:InvokeCommandAction Command="{Binding CanvasDragCompleted}"></core:InvokeCommandAction>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</GridView>
I have a view Model that is bind with ItemsControl. Inside that ItemsControl I have a stack panel. Now What I want is that selected item can be changed with arrow keys. Like in the attached picture I have 1st item selected and when I press down 4th item should be selected. The problem is that Items per row depends on screen resolution so On some screen there are 4 items per row and in some there are three. Secondly when I move down to the point where the page ends scroll should move down. How can I achieve this?.
Here is my xaml:
<ScrollViewer HorizontalAlignment="Center" VerticalScrollBarVisibility="Auto" Width="Auto" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" Grid.RowSpan="2" VerticalAlignment="Top" Margin="0,10,10,0">
<ItemsControl Name="productVariants">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<DockPanel MouseLeftButtonDown="ProductVariantClicked" Tag="{Binding VariantCBX}" Margin="8" MaxHeight="160" MaxWidth="200" MinWidth="200" MinHeight="160">
<Border Name="ItemBorder" CornerRadius="6" BorderBrush="Gray" Background="White" BorderThickness="2" DockPanel.Dock="Top">
<StackPanel Margin="0">
<TextBlock Name="ProductVariantOption" Text="{Binding VariantOption}" HorizontalAlignment="Center" FontWeight="Bold" FontSize="20"/>
<Image Source="{Binding ProductVariantLogoPath}" Height="80" Width="180" />
<TextBlock Text="{Binding VendorName}" HorizontalAlignment="Center" FontSize="15" FontWeight="Bold" />
<TextBlock Text="{Binding SellingPrice}" HorizontalAlignment="Center" FontSize="20" FontWeight="Bold" Foreground="Red" />
</StackPanel>
</Border>
</DockPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True" >
<Setter TargetName="ItemBorder" Property="BorderBrush" Value="Yellow"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
Like I said, I'm not aware of any clean way to do it. I might start by looking at the ActualWidth of your items (e.g. your "ItemBorder" Border element). If you know the ActualWidth of your item (plus any Horizontal Margin), and the ActualWidth of your ItemsControl, you can figure out how many elements are in one row at that moment. You would need to re-calculate this on-demand -- you could either recalculate this when a scroll is performed (because the sizes may have changed), or you could keep it up-to-date by re-calculating on layout change.
To find the ActualWidths, you have a couple of options. One is you could traverse through the visual descendants at scroll-time until you find the element that you care about. Another is you could subscribe to a"Loaded" event on and remember the actual width at that time, assuming that the widths don't change over time.
The problem is that the user interface (the ListBox) is not updated when new items enter its collection. I've a ListBox which is defined as follows:
<ListBox x:Name="ui_UserList" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SelectionChanged="ui_UserList_SelectionChanged" ItemsSource="{Binding chatUsers}" Grid.ColumnSpan="3" Margin="10,179,10,81" DataContext="{Binding}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Background="Transparent">
<TextBlock Text="{Binding nickname}" HorizontalAlignment="Center" TextAlignment="Center" FontSize="42" Grid.Row="0" Grid.Column="0" Foreground="Black" VerticalAlignment="Top" TextWrapping="Wrap"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The itemsource ChatUsers is an ObservableCollection. This was originally designed as an application for Windows Phone 8, where the ListBox equivalent works as expected (it updates when an item enters the collection).
Is there something about the ListBox that I've missed?
Ok, looks like I needed to set the DataContext explicitly even though it never complained about it.
The only change is this:
<ListBox x:Name="ui_UserList" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SelectionChanged="ui_UserList_SelectionChanged" ItemsSource="{Binding chatUsers}" Grid.ColumnSpan="3" Margin="10,179,10,81" DataContext="{StaticResource ChatUsersViewModel}">
.....
</ListBox>
I have a scedule with subjects in it. When I turn on a specific mode I want to change the opacity of certain subjects.
Therefore I have declared the property:
private double _sceduleOpacity;
public virtual double SceduleOpacity
{
get
{
if (_sceduleOpacity == 0) return 0.9;
else return _sceduleOpacity;
}
set { _sceduleOpacity = value; }
}
inside the Subject-Object.
When the mode is set, the SceduleOpacity-Property of the specific Subject is changed to the desired value (I've checked that).
Now all I need is a binding to that Property so that it is visible on the UI. But that is where the problem is. I've tried several approaches:
Bind it to the opacity of the DataTemplate:
GridView:
ItemTemplate="{Binding Mode=TwoWay, Source={StaticResource SceduleGridViewTemplate}}"
Resourcedictionary:
<DataTemplate x:Key="SceduleGridViewTemplate">
<Grid Background="{Binding ColorHash, Converter={StaticResource HexToSolidColorBrushConverter}}"
[...]
Opacity="{Binding SceduleOpacity}">
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
TextAlignment="Center"
FontSize="28"
Text="{Binding Name}"/>
</Grid>
This does not have any effect at all. But since the following binding:
<Grid [...]>
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
TextAlignment="Center"
FontSize="28"
Text="{Binding Name}"
Opacity="{Binding SceduleOpacity}"/>
</Grid>
sets the opacity of the displayed text successfully, I went on looking what the problem might be.
Bind it to the opacity of the Style or ItemContainerStyle:
I found out that the opacity of each GridView-Item is set by either in the Styles- or in the
ItemContainerStyle-Templates. But still the bindings do not work at all:
GridView:
Style="{Binding Source={StaticResource SceduleGridViewStyle}, Mode=TwoWay}">
Resourcedictionary:
<Style x:Key="SceduleItemStyle" TargetType="GridViewItem">
[...]
<Setter Property="Opacity" Value="{Binding SceduleOpacity}"/>
[...]</Style>
GridView:
ItemContainerStyle="{Binding Source={StaticResource SceduleItemStyle}, Mode=TwoWay}">
Resourcedictionary:
<Style x:Key="SceduleGridViewStyle" TargetType="GridView">
[...]
<Setter Property="Opacity" Value="{Binding SceduleOpacity}"/>
[...]</Style>
Do you have any idea on how I could fix that? Thank you very much!
It worked now. I have had to set the Opacity of the DateTemplate-Item as follows:
<Grid.Background>
<SolidColorBrush Color="{Binding ColorHash,
Converter={StaticResource HexToSolidColorBrushConverter}}"
Opacity="{Binding SceduleOpacity}"/>
</Grid.Background>
Thanks for help!