I'm trying to align a tabcontrol strip on the right.
Just to be clear - I want the tabs on the top (tabstripplacement), but aligned on the right.
The Headers for the TabItem's are located in a panel of type TabPanel. We can add HorizontalAlignment="Right" for it in the Resources of TabControl
<TabControl ...>
<TabControl.Resources>
<Style TargetType="TabPanel">
<Setter Property="HorizontalAlignment" Value="Right"/>
</Style>
</TabControl.Resources>
<!--...-->
</TabControl>
I don’t know why, but ItemsPanel replacement doesn’t work. You must replace template for whole TabControl:
<TabControl ItemsSource="{Binding Items}">
<TabControl.Template>
<ControlTemplate TargetType="TabControl">
<DockPanel LastChildFill="True">
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" HorizontalAlignment="Right" IsItemsHost="true"/>
<ContentPresenter ContentSource="SelectedContent"/>
</DockPanel>
</ControlTemplate>
</TabControl.Template>
<!-- This XAML doesnt work!-->
<!--<TabControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel HorizontalAlignment="Right" IsItemsHost="True"/>
</ItemsPanelTemplate>
</TabControl.ItemsPanel>-->
</TabControl>
Related
I'm new in wpf and mvvm, so i desided ask some help. And sorry, but english is not my native language.
I have main application for displaying some documents. Each document is an external dll + xml-file with data.
In main application i have XAML:
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Background="DarkGray">
<Border Margin="20" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="White" Padding="20">
<ContentControl x:Name="ccCurrentView" cal:View.Model="{Binding Path=CurrentView}"/>
</Border>
</ScrollViewer>
In ContentControl i display view of my document as UserControl from dll. And we use MVVM, so XAML of document is something like that:
<UserControl>
<StackPanel>
<UserControl_Type1 />
<UserControl_Type2 />...
</StackPanel>
<UserControl_Type3 />
</UserControl>
Any of these UserControl_TypeXXX can be inside its own dll.
Now users ask me replace StackPanel with WrapPanel for some type of UserControl. And, when user resize main application, some controls first wrap theirs elements and only then show scrollbars for all document.
But according to the information i've read WrapPanel doesn't wraps inside ScrollViewer.
How can i achieve this behavior if i don't have widht and height from main application and can't predict which UserControl inside my document should wrap theirs elements?
I found this article about xaml anti-patterns and it helps me a lot.
In my case I switch between two content template. One with ScrollViewer for old documents, another - without.
In Resources:
<DataTemplate x:Key="ResizableContent" >
<Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="DarkGray">
<Border Margin="20" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="White" Padding="20">
<ContentControl x:Name="ccCurrentView" cal:View.Model="{Binding Path=CurrentView}"/>
</Border>
</Border>
</DataTemplate>
<DataTemplate x:Key="NotResizableContent" >
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Background="DarkGray">
<Border Margin="20" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="White" Padding="20">
<ContentControl x:Name="ccCurrentView" cal:View.Model="{Binding Path=CurrentView}"/>
</Border>
</ScrollViewer>
</DataTemplate>
In MainPanel:
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource NotResizableContent}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsResizable}" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource ResizableContent}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
My listboxes are data driven from Lists of objects with databinding using a DataTemplate eg:
<ListBox x:Name="TheMainListBox"
ScrollViewer.IsVerticalRailEnabled="True"
ScrollViewer.IsHorizontalRailEnabled="False"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Height="540"
ItemsSource="{Binding}"
Width="Auto"
Margin="0"
Padding="0"
Background="Yellow"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto"
SelectionChanged="TheMainListBox_SelectionChanged"
DoubleTapped="TheMainListBox_DoubleTapped"
>
The template:
<ListBox.ItemTemplate>
<DataTemplate>
<Grid or Stackpanel Background="Blue"
Padding="0"
BorderBrush="Black"
BorderThickness="1"
Margin="0"
>
.... Binding Textboxes/blocks
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
I end up with a yellow container, the ListBox, .. with blue rectangles inside, the ListBox items but there is a vertical gap between them. I can set a negative vertical-top margin but that is cruddy and doesn't work for the top item. How can I reduce the vertical gap between items to zero.
If a create a ListBox with static items, each in a ListBoxItem container, eg:
<ListBoxItem BorderThickness="1" Width="100" Height="50"
BorderBrush="Black" Background="Red"/>
It all works as required.
So how can I get rid of the vertical spacing between items with the ItemTemplate/DataBinding?
This is mission critical, thx in advance.
I don't have time to load up a proj to test but you should be able to just kill the margin/padding that could cause it. So add;
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0"/>
</Style>
</ListBox.ItemContainerStyle>
I haven't thought a lot of why this could be happening, haven't digged into styles ither, and my answer doesn't look nice, but try Margin="0,-2,0,-2"
<DataTemplate>
<Grid or Stackpanel Background="Blue"
Padding="0"
BorderBrush="Black"
BorderThickness="1"
Margin="0,-2,0,-2"
>
.... Binding Textboxes/blocks
</Grid>
</DataTemplate>
properly setting the height of the ListBoxItem will solve the issue. Here is the code snippet
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Height" Value="Your_Desired_Height"/>
</Style>
</ListBox.ItemContainerStyle>
For listbox please use Height property and for listview use MinHeight property. Replace the required height value in the Your_Desired_Height placeholder.
I want to display data with level of detail, so i use a TreeView, but each detail is quite short, so i would like to use a WrapPanel (horizontal) to have many details per line.
Something like :
This is an unexpanded item
This is The Header of an expanded item
Info 1 Info 2 Info 3 Info 4
Info 5 Info 6 Info 7
So i tried defining TreeViewItem's Template but i could not get the wrappanel to
wrap. I have only one info per line, when info's datatemplate width is 100 and TreeView
is 500. i tried setting Width of WrapPanel, ItemsWidth, are other things with no success.
Any idea ?
EDIT : i finally got this to work with a 'simpler' solution. Still it seems that we
have to define the WrapPanel's Width, which make the solution less generic.
Here's the solution i came to : just defining, in a style, the ItemsPanel used in a
TreeViewItem :
<Style TargetType="TreeViewItem">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"
Width="520"
HorizontalAlignment="Stretch"
Margin="0"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
IsItemsHost="True"
/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
And i still let the not working solution here, for completeness sake.
(Why wouldn't it work ???)
<Style TargetType="TreeViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeViewItem">
<Grid Margin="2" Width="500">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentPresenter Name="PART_Header"
ContentSource="Header"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
!!!! this is the wrapanel not wrapping
<ListBox Name="AllItems" Grid.Row="1" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ItemsPresenter />
</ListBox>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="False">
<Setter
TargetName="AllItems"
Property="Visibility"
Value="Collapsed" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
EDIT : i finally got this to work with a 'simpler' solution. Still it seems that we
have to define the WrapPanel's Width, which make the solution less generic.
(Maybe a binding of the width (but which ?) would solve this)
Here's the solution i came to : just defining, in a style, the ItemsPanel used in a
TreeViewItem :
<Style TargetType="TreeViewItem">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"
Width="520"
HorizontalAlignment="Stretch"
Margin="0"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
IsItemsHost="True"
/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
You must set
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
to your
<TreeView/>
not for
<WrapPanel/>
example:
<TreeView x:Name="fieldTreeView" Grid.Row="1" Margin="5,0,5,0" Background="Beige"
ItemsSource="{Binding Source={StaticResource bla}}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<TreeView.Resources>
<DataTemplate DataType="{x:Type Model:bla}">
<StackPanel Orientation="Vertical">
<Label Content="{Binding Name}"/>
<TextBox Text=""/>
</StackPanel>
</DataTemplate>
</TreeView.Resources>
<TreeView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</TreeView.ItemsPanel>
</TreeView>
This solution works for me.
Try
Disable the scroll bars
Widen the WrapPanel and see the visual impact, is it effected?
Make a color border/background to track the actual size of the WrapPanel
These will help you trace the problem
I have a CustomControl (say CC) that has been inherited from ContentControl and contains a ScrollViewer which includes a ContentPresenter. When I put a ListBox into the CC it works without any problem. But when I set the ItemsPanelTemplate of the ListBox it doesn't notify CC to scroll into the ListBox selected item.
What's the reason for it? -Thanks
UPDATE:
I'll encounter the problem described above only if I set HorizontalScrollBarVisibility or VerticalScrollBarVisibility to Hidden and customize the ItemsPanelTemplate of the ListBox simultaneously. (I need to hide scollbars.)
I wonder if hiding Scrollbars prevents ScrollViewer contents from notifying it to bring selected item into view, why this issue doesn't happen when I don't change items panel???
Generic.xaml:
<ResourceDictionary ...>
<Style TargetType="{x:Type local:CustomControl1}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<Border ...>
<ScrollViewer ...
CanContentScroll="True"
HorizontalScrollBarVisibility="Hidden" « PROBLEM
VerticalScrollBarVisibility="Hidden"> «
<ContentPresenter Content="{TemplateBinding Content}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
MainWindow.xaml:
<Window x:Class="MyNamespace1.MainWindow"
...
xmlns:proj="clr-namespace:MyNamespace0;assembly=...">
<Grid>
<proj:CustomControl1 x:Name="CC">
<ListBox>
<ListBox.ItemsPanel> «
<ItemsPanelTemplate> «
<StackPanel Orientation="Horizontal"/> « PROBLEM
</ItemsPanelTemplate> «
</ListBox.ItemsPanel> «
<!--content goes here-->
</ListBox>
</proj:CustomControl1>
</Grid>
</Window>
Have you set the IsItemsHost property for the Panel in the ItemsPanelTemplate to True?
E.g. if the itemspaneltemplate should use a Canvas:
<ItemsPanelTemplate>
<Canvas IsItemsHost="True" />
</ItemsPanelTemplate>
Related
StackPanel treats its content has having infinite space..
You will have to limit its size explicitly, or change it to other panel, Grid for example.
Try this:
<ItemsPanelTemplate>
<Grid/>
</ItemsPanelTemplate>
Or:
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Width="100" Height="100"/>
</ItemsPanelTemplate>
I'm sure this is dead simple, but I can't seem to figure it out.
I have a ListBox to display items, and these are displayed with a DataTemplate. I now want to group these items, so have added a group based on the manufacturer property. This is done in code behind.
ICollectionView view = CollectionViewSource.GetDefaultView(Items);
PropertyGroupDescription groups = new PropertyGroupDescription("Manufacturer");
view.GroupDescriptions.Add(groups);
I wanted to have each group in an expander, so they can be hidden. I have got this working by looking at GroupTemplates at MSDN This involves, having an expander, textblock and then a seperator to rule off the extra space like in Windows Vista/7 Groups. As Below.
The problem I am having is I cannot get the separator to fill up the remaining space correctly. If I use a MinWidth value, all my expanders have the same width. If I use the {binding ActualWidth, ElementName=MyListBox}, then the separator is too wide, as its as wide as the control that contains it. So it sets the scroll bars to be visible, (see screenshot below). If i leave width blank, then the seperator is not drawn at all.
My gut feeling is the stackpanel should have expanded the seperator to use the remaining space but it didn't. So i tried a DockPanel as in the XamlCode below, yet this also fails. I have a few other problems with getting controls to fill up the remaining space, by using a suitable width so if you can help me resolve this, it would be great.
My current WPF Xaml Markup. You will need to add elements to get this to display something.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel x:Name="myStackPanel">
<ListBox x:Name="MyListBox">
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True">
<Expander.Header>
<DockPanel HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Height="Auto"
Width="{Binding ActualWidth, ElementName=MyListBox}"
Margin="10">
<TextBlock DockPanel.Dock="Left" Margin="0" FontSize="14" FontWeight="Bold" Foreground="Black" Text="{Binding Path=Name}"/>
<Separator DockPanel.Dock="Right" Margin="4,0,4,0"></Separator>
</DockPanel>
</Expander.Header>
<ItemsPresenter Margin="5,0,0,0" />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<!-- Data Template Here -->
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</ScrollViewer>
It is in fact not trivial, the control template of the Expander consists of a ToggleButton as the Header and a ContentPresenter for the content. The problem is that the ToggleButton itself has a special style & template which contains the arrow that has the alignment hard-coded into it, the default one looks something like this:
<Style x:Key="ExpanderDownHeaderStyle"
TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Padding="{TemplateBinding Padding}">
<Grid Background="Transparent"
SnapsToDevicePixels="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="19"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- ... -->
<!-- The HorizontalAlignment needs to be set to stretch here -->
<ContentPresenter Grid.Column="1"
Margin="4,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
SnapsToDevicePixels="True"
RecognizesAccessKey="True"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<!-- ... -->
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
To get your style to work you need to modify the default Expander template (get default templates on MSDN - Default WPF Themes link). Not nice but you don't really have much of a choice.