I have a problem autosizing the (Text)Content of my buttons.
This is the style of my Buttons. Nothing special but notice the TextWrapping property!
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<TextBlock Text="{TemplateBinding Content}" TextWrapping="Wrap"/>
</Setter.Value>
</Setter>
</Style>
I defined a ItemTemplate based on my Buttons:
<DataTemplate x:Key="MyItemTemplate">
<Button Content="{Binding Content}" Command="{Binding Command}" FontWeight="Bold" FontSize="{Binding FontSize}"/>
</DataTemplate>
I am showing a list of items in with a ItemsControl with 3 columns:
<ItemsControl ItemsSource="{Binding MyItems}" ItemTemplate="{StaticResource MyItemTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="3"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Until this point, this is nothing special. But now, I want the FontSize of all my Buttons stretched to maximum possible, the item with the largest content allows (all items should have the same FontSize in the end).
I found a solution to calculate the needed size of a text. So I could calculate the maximum FontSize of a Button. But therefore I need the actual size of one of my Buttons (all have the same size).
I have not really an idea how to get the size and solve my problem. Would be great if anybody has an idea - or a totally different approach.
You can use ActualWidth of your Button as CommandParameter to get the width like this :
<UserControl ....
.................>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding Command}" CommandParameter="{Binding ActualWidth,ElementName=button}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<DataTemplate x:Key="MyItemTemplate">
<Button Content="{Binding Content}" x:Name="button"
Command="{Binding Command}"
FontWeight="Bold" FontSize="{Binding FontSize}"/>
</DataTemplate>
your Command should then be like this :
public ICommand Command => new DelegateCommand<object>(ExecuteCommand);
private void ExecuteCommand(object obj)
{
double width = (double)obj;
}
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.
Following on from this question (DataTemplateSelector for Uniform Grid binding?), I still am not getting my Buttons/Textblocks to adhere to the row and the column that they are bound to in the view model. I will only post the XAML as I know the row and column bindings are correct (Live Visual Tree tells me Row is 1 and Column is 1 for example, but on the grid it shows otherwise...).
If you need anymore code let me know. This is the small bit of XAML.
<Grid DockPanel.Dock="Left" Background="Transparent" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinWidth="800" Height="400">
<ItemsControl ItemsSource="{Binding ObjCompositeCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid DockPanel.Dock="Top" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Name="objGrid" Grid.Row="1"
Rows="{Binding RowCount}"
Columns="{Binding ColumnCount}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Row" Value="{Binding Row}"/>
<Setter Property="Grid.Column" Value="{Binding Column}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type engine:ObjA}">
<Button Content="{Binding Id}" />
</DataTemplate>
<DataTemplate DataType="{x:Type engine:GridLabeller}">
<TextBlock Text="{Binding HeaderName}"/>
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
</Grid>
A UniformGrid in WPF doesn't care about the Grid.Row and Grid.Column attached properties. You need to create a Grid with RowDefinitions and ColumnsDefinitions for setting these properties to have any effect.
You may create a Grid programmatically in the view based on the values of the RowCount and ColumnCount source properties.
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>
Trying to get some keybindings onto my ListBoxItems in a ListBox in WPF. I am using MVVM, and binding the ItemSource of the ListBox to a list of ViewModels. This ViewModel has a string and a boolean for 'Selected'. I wish to display Selected as a property to a CheckBox.
I am trying to make it so that if I navigate the list items with the up and down arrows on the keyboard, and then press enter/space/whatever, I can toggle the Checkbox. However, I have to press tab first, to get focus to the StackPanel which contains the checkbox.
<DataTemplate x:Key="MyTemplate" DataType="{x:Type ViewModel}">
<Border Width="2" BorderBrush="Blue">
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyUp">
<i:InvokeCommandAction Command="{Binding EnterCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<CheckBox VerticalAlignment="Center"
Content="{Binding Name}"
IsChecked="{Binding Selected}"
Margin="3" />
</Border>
</DataTemplate>
=======================
<Popup x:Name="FilterPopup" Grid.Column="1"
IsOpen="{Binding IsChecked, ElementName=FilterButton}"
StaysOpen="False"
PlacementTarget="{Binding ElementName=FilterButton}"
Placement="Top">
<ListBox ItemsSource="{Binding ViewModels}"
ItemTemplate="{StaticResource MyTemplate}" />
</Popup>
Have I missed something obvious???
The triggers above are fired inside the data template, not inside item container. So if the last one is focused there is no effect.
To avoid this, the triggers should be specified on item container level:
<ListBox.ItemContainerStyle>
<Style>
<Setter Property="l:Attach.InputBindings">
<Setter.Value>
<InputBindingCollection>
<KeyBinding Command="{Binding EnterCommand}" Key="Enter" />
<KeyBinding Command="{Binding EnterCommand}" Key="Space" />
</InputBindingCollection>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
I've taken a way to set input bindings from style from this question.
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.