How to align multiple StatusBarItems to the right side in XAML? - c#

I have a StatusBar with 4 items in it on my C# application. I basically want to float the last two StatusBarItems to the right. I've tried it by setting them both with HorizontalAlignment="Right", but that did only work for the last item.
<StatusBar Name="statusBar1" Height="23" HorizontalAlignment="Stretch"
VerticalAlignment="Bottom">
<StatusBarItem />
<StatusBarItem />
<StatusBarItem HorizontalAlignment="Right" />
<StatusBarItem HorizontalAlignment="Right" />
</StatusBar>
I started googling and I came up with the following URL:
Blogspot
Is this really the only solution for this, or is there an easier way?

You can take advantage of the fact that the default ItemsPanel for the StatusBar is the DockPanel. The DockPanel will, by default, try to fill the remaining space with the last item. So the last StatusBarItem you add to the StatusBar will fill the remainder of the space. To take advantage of this, you can simply nest StatusBarItems like this:
<StatusBar Name="statusBar1" Height="23" HorizontalAlignment="Stretch" VerticalAlignment="Bottom">
<StatusBarItem Content="Item 1"/>
<StatusBarItem Content="Item 2" />
<StatusBarItem HorizontalAlignment="Right">
<StackPanel Orientation="Horizontal">
<StatusBarItem Content="Item 3"/>
<StatusBarItem Content="Item 4"/>
<ProgressBar Height="15" Width="50" IsIndeterminate="True" Margin="5,0"/>
</StackPanel>
</StatusBarItem>
</StatusBar>
Note that the HorizontalAlignment of the 3rd StatusBarItem is set to Right so that it's content will be right-aligned.
Of course, you don't have to have Item 3 and Item 4 be StatusBarItems, they could be other controls, such as Buttons or ProgressBar as I've demonstrated above as well. The StatusBarItem is simply a container that wraps items in a StatusBar, similar to how a ComboBoxItem wraps items inside of a ComboBox.
The StatusBar will wrap it's contents in StatusBarItems automatically, if you don't use them, so items 1 and 2 could just as easily be TextBoxes. The primary reason to use StatusBarItems is in the case where you want to control how the StatusBarItem works, like in the 3rd StatusBarItem where it sets the HorizontalAlignment manually, rather than rely on the default.

As mentioned, the default container is DockPanel. As such, you can set as many items as needed to DockPanel.Dock="Right". Just be sure that the fill item is last.
<StatusBar>
<StatusBarItem DockPanel.Dock="Right">
<Slider Width="100" />
</StatusBarItem>
<StatusBarItem DockPanel.Dock="Right">
<Label>Zoom: 100 %</Label>
</StatusBarItem>
<StatusBarItem>
<TextBlock>Ready</TextBlock>
</StatusBarItem>
</StatusBar>

You can also set LastChildFill to false and then use DockPanel.Dock=Right just like the solution above, without having to worry about the last item consuming all the space:
<StatusBar>
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<DockPanel LastChildFill="False" />
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
</StatusBar>

Another interesting way of achieving this is to replace default panel of StatusBar with Grid, which will give you far more control over the layout of items.
<StatusBar Height="30">
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem Grid.Column="0">
<TextBlock Text="{Binding ProgressMessage, Mode=OneWay}" />
</StatusBarItem>
<StatusBarItem Grid.Column="1">
<ProgressBar Value="{Binding ProgressValue, Mode=OneWay}" Width="100" Height="10" />
</StatusBarItem>
<StatusBarItem Grid.Column="2">
<Ellipse Width="12" Height="12" Stroke="Gray" Fill="Red" />
</StatusBarItem>
</StatusBar>

Related

How to add a separator to the Expander component in UWP app?

I'm looking for a way of implementing this kind of separator to the expander component in UWP app:
Any ideas how to do that?
I've managed to create the similar look of the expander, but I don't know how to implement separators?
Also, I would like to learn how to make expanders kind of "push" other components down when I expand them, so they don't overlap with other components, but simply move them.
Here's the XAML code for this expander:
<muxc:Expander x:Name="FontExpander"
x:Uid="FontExpander"
Width="1155"
IsExpanded="True"
Margin="22,323,0,0"
VerticalAlignment="Top"
Grid.Row="2"
Height="380"
HorizontalContentAlignment="Left"
ExpandDirection="Down">
<muxc:Expander.Header>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<FontIcon Margin="0,0,12,0"
VerticalAlignment="Center"
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
FontSize="16"
Glyph=""/>
<StackPanel Grid.Column="1"
Margin="0,12"
Orientation="Vertical">
<TextBlock x:Uid="SettingsFontTitle" Style="{StaticResource BodyTextBlockStyle}"/>
<TextBlock x:Uid="SettingsFontDescription"
Style="{StaticResource CaptionTextBlockStyle}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
TextWrapping="WrapWholeWords"/>
</StackPanel>
</Grid>
</muxc:Expander.Header>
<muxc:Expander.Content>
<Grid Margin="-18,-170,-17,-170">
<TextBlock x:Name="SettingsFamily" x:Uid="SettingsFamily" Text="Family" Margin="50,51,1000,286"/>
<ComboBox x:Name="ComboBoxFamily" ItemsSource="{x:Bind Fonts}" Width="200" Margin="950,41,0,0" SelectionChanged="ComboBoxFamily_SelectionChanged" />
<TextBlock x:Name="SettingsStyle" x:Uid="SettingsStyle" Text="Style" Margin="50,106,995,218" Loaded="SettingsStyle_Loaded"/>
<ComboBox x:Name="ComboBoxStyle" Width="200" Margin="950,101,0,0">
<x:String>Regular</x:String>
</ComboBox>
<TextBlock x:Name="SettingsSize" x:Uid="SettingsSize" Text="Size" Margin="50,166,1002,158"/>
<ComboBox x:Name="ComboBoxSize" ItemsSource="{x:Bind FontSizes}" Width="200" Margin="950,161,0,0"/>
<TextBlock x:Name="Text" x:Uid="SettingsText" Text="Hello World! I am so excited to be here!" Margin="62,224,38,126" TextWrapping="Wrap" FontSize="{x:Bind (x:Double)ComboBoxSize.SelectedValue, Mode=OneWay}" TextAlignment="Center"/>
</Grid>
</muxc:Expander.Content>
</muxc:Expander>
Any help would be much appreciated!
A separate can for example be implemented using a Border or a Grid:
<Grid Background="DarkGray" Height="1" />
As a side note, you shouldn't use margins to position your elements. Use an appropriate layout Panel. Using a Grid, you should add ColumnDefinitions and RowDefinitions to it as examplified here.

DockPanel - Stretch control to fill remaining space in respect to it's siblings Visibility

The following snippet produces this result:
<DockPanel Width="240">
<ComboBox HorizontalAlignment="Stretch">
<ComboBoxItem Content="A" />
<ComboBoxItem Content="B" />
<ComboBoxItem Content="C" />
</ComboBox>
</DockPanel>
As we can see, the ComboBox fills the entire DockPanel width nicely, as it's supposed to be.
If we add the following StackPanel right after the ComboBox, we would have this:
<StackPanel Orientation="Horizontal" Width="120" Visibility="Visible" Background="Aqua">
<TextBox Width="60" />
<TextBox Width="60" />
</StackPanel>
We've just got into the first problem: shouldn't the ComboBox fill the other 120 pixels of the DockPanel, due to it's HorizontalAlignment=Stretch and since the StackPanel uses the other 120?
Least, if we turn our StackPanel.Visibility into Hidden/Collapsed, we would have this:
How can I make the ComboBox to fill the entire DockPanel.Width HORIZONTALLY, just like the first image, when the StackPanel.Visibility is Hidden/Collapsed?
All the controls must be horizontally aligned and a DockPanel isn't mandatory to achieve this.
We've just got into the first problem: shouldn't the ComboBox fill the other 120 pixels of the DockPanel, due to it's HorizontalAlignment=Stretch and since the StackPanel uses the other 120?
Only if it the last child of the DockPanel:
<DockPanel Width="240">
<StackPanel Orientation="Horizontal" Width="120" Visibility="Visible" Background="Aqua"
DockPanel.Dock="Right">
<TextBox Width="60" />
<TextBox Width="60" />
</StackPanel>
<ComboBox>
<ComboBoxItem Content="A" />
<ComboBoxItem Content="B" />
<ComboBoxItem Content="C" />
</ComboBox>
</DockPanel>
There is no reason to explicitly set the HorizontalAlignment property to Stretch by the way. This is the default value.
How can I make the ComboBox to fill the entire DockPanel.Width HORIZONTALLY, just like the first image, when the StackPanel.Visibility is Hidden/Collapsed?
By adding the ComboBox as the last child as per the above sample markup.
If i understand you, in your case it seems that Grid component will be a good choice.
For the space issue -
Visibility = "Hidden" keeps the original component space "alive", then if it possible - use Visibility = "Collapsed" instead
<Grid Width="240">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<ComboBox HorizontalAlignment="Stretch">
<ComboBoxItem Content="A" />
<ComboBoxItem Content="B" />
<ComboBoxItem Content="C" />
</ComboBox>
<StackPanel Grid.Column="1" Orientation="Horizontal" Visibility="Visible" Background="Red">
<TextBox Width="60" />
<TextBox Width="60" />
</StackPanel>
</Grid>

AvalonDock 2.2 - Full width TitleTemplate (fill parent container)

Hy everyone!
I created a title template in AvalonDock 2.2 (WPF Toolkit). The problem is that the context menu of the LayoutAnchorable is only triggered when I right-click on the part of the title that contains something (and not the entire width of the anchorable).
Here is the relevant code segment I'm using now:
<ad:DockingManager x:Class="Pdn.Gui.Docking.Control.DockingSystem" ...
AnchorablesSource="{Binding Path=Panels}">
<ad:DockingManager.Resources>
<DataTemplate x:Key="DockingWindowTitleDataTemplate" DataType="{x:Type ad:LayoutContent}">
<StackPanel ToolTip="{Binding Path=Content.ToolTip}" Orientation="Horizontal" HorizontalAlignment="Stretch">
<Image MaxHeight="16" MaxWidth="16" VerticalAlignment="Center"
Source="{Binding Path=Content.IconSource, Converter={StaticResource IconToImageSourceConverter}}" />
<TextBlock Text="{Binding Path=Content.Name}" Margin="5,0,0,0" VerticalAlignment="Center"/>
<TextBlock Text="*" Visibility="{Binding Path=Content.DirtySignVisibility}" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="DockingWindowTitleGridDataTemplate" DataType="{x:Type ad:LayoutContent}">
<Grid ToolTip="{Binding Path=Content.ToolTip}" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" MaxHeight="16" MaxWidth="16" VerticalAlignment="Center"
Source="{Binding Path=Content.IconSource, Converter={StaticResource IconToImageSourceConverter}}" />
<TextBlock Grid.Column="1" Text="{Binding Path=Content.Name}" Margin="5,0,0,0" VerticalAlignment="Center"/>
<TextBlock Grid.Column="2" Text="*" Visibility="{Binding Path=Content.DirtySignVisibility}" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="DefaultPanelTitle">
<TextBlock Text="{Binding Path=Content.Name}" TextTrimming="CharacterEllipsis" />
</DataTemplate>
...
</ad:DockingManager.Resources>
<ad:DockingManager.AnchorableTitleTemplate>
<StaticResource ResourceKey="DockingWindowTitleDataTemplate" />
</ad:DockingManager.AnchorableTitleTemplate>
...
</ad:DockingManager>
When I use the DefaultPanelTitle template (which is the default template of the theme) everything is fine, the context menu is triggered on the full width of the title part.
However when I use the other two templates (Image-Name-IsDirty elements), the context menu is triggered only on the beginning of the title area (and not right to the asterix).
I'm guessing I should tell the container to fill its parent container, but I can't figure out how. I used StackPanel, Grid, DockPanel (LastChildFill = "True") with HorizontalAlignment set to Stretch. What kind of container should I use?
What am I missing?
P.S.: I can only respond to your answers for another 12 hours, then I'm gone for a while (week). But I'm not abandoning this question until it's answered :) Thanks for your patience.
Well, the solution was quite simple. I wrapped the StackPanel in a Label. Now the context menu can be triggered on every pixel in the title part. The template now looks like this:
<ad:DockingManager x:Class="Pdn.Gui.Docking.Control.DockingSystem" ...
AnchorablesSource="{Binding Path=Panels}">
<ad:DockingManager.Resources>
<DataTemplate x:Key="DockingWindowTitleDataTemplate" DataType="{x:Type ad:LayoutContent}">
<Label>
<StackPanel ToolTip="{Binding Path=Content.ToolTip}" Orientation="Horizontal" HorizontalAlignment="Stretch">
<Image MaxHeight="16" MaxWidth="16" VerticalAlignment="Center"
Source="{Binding Path=Content.IconSource, Converter={StaticResource IconToImageSourceConverter}}" />
<TextBlock Text="{Binding Path=Content.Name}" Margin="5,0,0,0" VerticalAlignment="Center"/>
<TextBlock Text="*" Visibility="{Binding Path=Content.DirtySignVisibility}" VerticalAlignment="Center"/>
</StackPanel>
</Label>
</DataTemplate>
...
</ad:DockingManager.Resources>
<ad:DockingManager.AnchorableTitleTemplate>
<StaticResource ResourceKey="DockingWindowTitleDataTemplate" />
</ad:DockingManager.AnchorableTitleTemplate>
...
</ad:DockingManager>
I love simple solutions.

How to change GridView.ItemTemplate while app is running?

In my app I have page with GridView and ComboBox. I want to change GridView.ItemTemplate property according to selected item in ComboBox. How should I implement it?
btw, I know about this question, but it is quite old and it does not look like "best practice". (How visibility/invisibility of ui control affects cpu/gpu load?)
My GridView:
<GridView x:Name="gridViewMain" Grid.Row="1" SelectionMode="None" IsItemClickEnabled="True"
ItemsSource="{Binding CurrentList}" ItemTemplate="{StaticResource gridViewMainItemTemplate}"
Loaded="gridViewMain_Loaded" LayoutUpdated="gridViewMain_LayoutUpdated">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="ItemClick">
<core:CallMethodAction MethodName="GridViewClick"
TargetObject="{Binding Mode=OneWay}" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</GridView>
One of my templates:
<DataTemplate x:Key="gridViewMainItemTemplate">
<Grid x:Name="gridATemplate" Width="185" Height="288">
<Image x:Name="imgATemplate" Source="{Binding image_url}" Stretch="UniformToFill"
HorizontalAlignment="Center" VerticalAlignment="Center" />
<Grid Background="{ThemeResource ListViewItemOverlayBackgroundThemeBrush}" VerticalAlignment="Bottom">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock x:Name="textBlockTitle" Text="{Binding title}"
TextWrapping="Wrap" Style="{StaticResource BodyTextBlockStyle}" Margin="5,0,0,0"
Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Foreground="White" FontWeight="Bold"
MaxHeight="50" />
<TextBlock x:Name="textBlockType" TextWrapping="Wrap" Style="{StaticResource BodyTextBlockStyle}"
Margin="5,0,0,0"
Grid.Column="0" Grid.Row="1" Foreground="White" Text="{Binding type}" FontWeight="Bold" />
<StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal">
<TextBlock x:Name="textBlockProgressL" TextWrapping="Wrap"
Style="{StaticResource BodyTextBlockStyle}" FontWeight="Bold" Foreground="White"
Text="Progress:" />
<TextBlock x:Name="textBlockProgressV" TextWrapping="Wrap"
Style="{StaticResource BodyTextBlockStyle}" FontWeight="Bold" Foreground="White"
Text="{Binding watched_episodes}" Margin="10,0,0,10" />
</StackPanel>
</Grid>
</Grid>
</DataTemplate>
Sure you can do this! In XAML you can do anything. What you cannot do is change the Template on the fly without re-rendering. Remember, this is like telling your printer to use card stock. It will obey. If you change the setting to use notebook paper, it will obey that, too. You will just have to print again since it has already printed on card stock.
There are a few ways for you to re-render a GridView. One way is to navigate away from the page and navigate back. That's not ideal sounding in your scenario. Odds are, in your scenario, you just need to reset the ObservableCollection you are using. Like this:
void Reset<T>(ObservableCollection<T> collection)
{
var original = collection.ToArray();
collection.Clear();
foreach (var item in original)
collection.Add(item);
}
Best of luck!
You'll want to use datatemplateselector
http://blogs.msdn.com/b/bryanbolling/archive/2012/12/08/how-to-control-the-datatemplateselector-in-windows-store-apps.aspx
You can create multiple itemtemplates and choose which one to display based on any condition.
You'll have to refresh the gridview whenever the selection changes.

multiple stackpanels in ScrollViewer Windows 8 XAML

I seem to be having a problem with adding multiple StackPanels in a ScrollViewer. I can add the first one and it displays the data I want but when I try to add the second StackPanel is fails and brings the error "Duplication assignment to the 'Content' property of the 'ScrollViewer' object"
My front end code is like below:
<ScrollViewer VerticalScrollBarVisibility="Visible"
HorizontalScrollBarVisibility="Visible"
ZoomMode="Disabled"
Grid.Column="1"
Grid.Row="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<StackPanel Style='{StaticResource BlueFirstStackPanel}'>
<TextBlock Text='Facility Patient Number:'
Style='{StaticResource TextBlockStyle}' />
<TextBox Style='{StaticResource TextBoxStyle}' />
<TextBlock Text='Patient Number:'
Style='{StaticResource TextBlockStyle}' />
<TextBox Style='{StaticResource TextBoxStyle}' />
<TextBlock Text='Patient Support Number:'
Style='{StaticResource TextBlockStyle}' />
<TextBox Style='{StaticResource TextBoxStyle}' />
<TextBlock Text='NHIF Number:'
Style='{StaticResource TextBlockStyle}' />
<TextBox Style='{StaticResource TextBoxStyle}' />
<TextBlock Text='Patient National ID:'
Style='{StaticResource TextBlockStyle}' />
<TextBox Style='{StaticResource TextBoxStyle}' />
</StackPanel>
</ScrollViewer>
My C# code for the code has this in it:
public sealed class ScrollViewer : ContentControl
{
}
And the above displays very well but when I add a second StackPanel it brings an error. Any help with this?
The ScrollViewer can only have one child control. Try wrapping both StackPanels in a Grid or another StackPanel:
<ScrollViewer>
<StackPanel x:Name="ScrollViewerChild">
<StackPanel x:Name="StackPanel1">
</StackPanel>
<StackPanel x:Name="StackPanel2">
</StackPanel>
</StackPanel>
</ScrollViewer>

Categories