In my app, I have a tabbed layout (PivotHeaderItem) similar to the Windows Store app. Also similar to the Windows Store app, I have set the Selected tab's text to become bold. However, when the text becomes bold, the item's width becomes slightly bigger, causing the other tabs to shift slightly; I'm wanting to prevent this from happening.
I'm using my own FormsPivot.HeaderTemplate, which is here (in my custom TabbedPageRenderer):
private Windows.UI.Xaml.DataTemplate GetStyledHeaderTemplateDesktop(TabbedPage element)
{
var sb = new StringBuilder();
sb.Append("<DataTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"");
sb.Append(" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">");
sb.Append("<TextBlock Text=\"{Binding Title}\" Padding=\"12 0 12 0\" FontFamily=\"{ThemeResource ContentControlThemeFontFamily}\" FontSize=\"16\" />");
sb.Append("</DataTemplate>");
return (Windows.UI.Xaml.DataTemplate)XamlReader.Load(sb.ToString());
}
As for how I set the text to Bold, in my UWP project's App.xaml file, I added the default style for the PivotHeaderItem, and then added the following code to the VisualState's Storyboard for the Selected, SelectedPressed, and SelectedHovered states:
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="FontWeight" >
<DiscreteObjectKeyFrame KeyTime="0" Value="SemiBold" />
</ObjectAnimationUsingKeyFrames>
However, when the text becomes bold, the item's width becomes slightly bigger, causing the other tabs to shift slightly; I'm wanting to prevent this from happening.
To avoid the item's width from resizing, you can give the ContentPresenter witch is in the default style for the PivotHeaderItem a fixed Width to include the header item content.
<ContentPresenter x:Name="ContentPresenter" Width="96"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
FontSize="{TemplateBinding FontSize}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
OpticalMarginAlignment="TrimSideBearings" />
Similar principle, you can also give a border to contain the ContentPresenter then configure the border with a appropriate Width.
<Border BorderBrush="Red" BorderThickness="5" Width="96" >
<ContentPresenter x:Name="ContentPresenter"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
FontSize="{TemplateBinding FontSize}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
OpticalMarginAlignment="TrimSideBearings" />
</Border>
Breeze Liu - MSFT's solution works, however I didn't want to specify a fixed width (forgot to mention that in the OP).
What I decided to do was to update the HeaderItemTemplate to include two TextBlock objects; one for the text that would change from bold/not bold, and another with the same text, but is always bold, as well as having an opacity of 0. I put them into a grid so the TextBlocks would sit on top of one another. Because the invisible (Opacity = 0) TextBlock underneath is always bold, the width will not change when the visible TextBlock becomes bold. A bit hacky, but it gets the job done...
private Windows.UI.Xaml.DataTemplate GetStyledHeaderTemplateDesktop(TabbedPage element)
{
var sb = new StringBuilder();
sb.Append("<DataTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"");
sb.Append(" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">");
sb.Append("<TextBlock Text=\"{Binding Title}\" Padding=\"12 0 12 0\" FontFamily=\"{ThemeResource ContentControlThemeFontFamily}\" FontSize=\"16\" />");
sb.Append("<TextBlock Text=\"{Binding Title}\" Padding=\"12 0 12 0\" FontFamily=\"{ThemeResource ContentControlThemeFontFamily}\" FontSize=\"16\" FontWeight=\"SemiBold\" Opacity=\"0\" />");
sb.Append("</DataTemplate>");
return (Windows.UI.Xaml.DataTemplate)XamlReader.Load(sb.ToString());
}
Related
I am developing an UWP app. I used a ProgressRing as below code:
<ListViewItem Template="{ThemeResource SeetingsListItemContentThemeStyle}"
BorderBrush="{ThemeResource SettingsListItemBorderThemeColor}"
BorderThickness="0,0,0,1"
AutomationProperties.SizeOfSet="0"
AutomationProperties.Name="{Binding SettingsAutomationText, Mode=OneWay}">
<ProgressRing VerticalAlignment="Center"
Margin="18, 0, 0, 14"
Height="21"
Width="21"
IsActive="True"
Foreground="Red"
Visibility="Visible"/>
</ListViewItem>
"SeetingsListItemContentThemeStyle" is as below:
For Light Theme:
<ControlTemplate x:Key="SeetingsListItemContentThemeStyle" TargetType="ListViewItem">
<ListViewItemPresenter x:Name="Root"
CheckBrush="{ThemeResource ListViewItemCheckBrush}"
ContentMargin="{TemplateBinding Padding}"
CheckBoxBrush="{ThemeResource ListViewItemCheckBoxBrush}"
CheckMode="{ThemeResource ListViewItemCheckMode}"
FocusBorderBrush="{ThemeResource ListViewItemFocusBorderBrush}"
FocusSecondaryBorderBrush="{ThemeResource ListViewItemFocusSecondaryBorderBrush}"
HorizontalContentAlignment="Left"
Control.IsTemplateFocusTarget="False"
PressedBackground="#12000000"
PlaceholderBackground="{ThemeResource ListViewItemPlaceholderBackground}"
PointerOverBackground="#08000000"
SelectionCheckMarkVisualEnabled="{ThemeResource ListViewItemSelectionCheckMarkVisualEnabled}"
SelectedPressedBackground="#12000000"
SelectedPointerOverBackground="#08000000"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
</ListViewItemPresenter>
</ControlTemplate>
For Dark Theme:
<ControlTemplate x:Key="SeetingsListItemContentThemeStyle" TargetType="ListViewItem">
<ListViewItemPresenter x:Name="Root"
CheckBrush="{ThemeResource ListViewItemCheckBrush}"
ContentMargin="{TemplateBinding Padding}"
CheckBoxBrush="{ThemeResource ListViewItemCheckBoxBrush}"
CheckMode="{ThemeResource ListViewItemCheckMode}"
FocusBorderBrush="{ThemeResource ListViewItemFocusBorderBrush}"
FocusSecondaryBorderBrush="{ThemeResource ListViewItemFocusSecondaryBorderBrush}"
HorizontalContentAlignment="Left"
Control.IsTemplateFocusTarget="False"
PressedBackground="#12ffffff"
PlaceholderBackground="{ThemeResource ListViewItemPlaceholderBackground}"
PointerOverBackground="#08ffffff"
SelectionCheckMarkVisualEnabled="{ThemeResource ListViewItemSelectionCheckMarkVisualEnabled}"
SelectedPressedBackground="#12ffffff"
SelectedPointerOverBackground="#08ffffff"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
</ListViewItemPresenter>
</ControlTemplate>
The progress ring is showing correctly when the parent page loads. But it is not showing when I change theme from System. Once this issue occurs, Progress Ring not shows for Light-Dark both themes. If I go back to some other pages and come back to this page again, this time progress ring shows correctly.
Can anyone please help me to work Progress Ring correctly after theme change in app runtime?
ProgressRing not showing when Theme changed in runtime
I think the problem is the ProgressRing ring animation was be destroy when you change ListViewItem's ControlTemplate by update current system theme. For this scenario, you could reload current page to rebuild this animation after the theme change.
private void Button_Click(object sender, RoutedEventArgs e)
{
Reload();
}
public bool Reload() { return Reload(null); }
private bool Reload(object param)
{
Type type = this.Frame.CurrentSourcePageType;
if (this.Frame.BackStack.Any())
{
type = this.Frame.BackStack.Last().SourcePageType;
param = this.Frame.BackStack.Last().Parameter;
}
try { return this.Frame.Navigate(type, param); }
finally { this.Frame.BackStack.Remove(this.Frame.BackStack.Last()); }
}
Usage
public MainPage()
{
this.InitializeComponent();
var Listener = new ThemeListener();
Listener.ThemeChanged += Listener_ThemeChanged;
}
private void Listener_ThemeChanged(ThemeListener sender)
{
Reload();
}
I've searched accross the Internet to solve the follow problem, but unfortunately I didn't found any working solution.
My goal is to have an ImageBrush with an image x-repeating at the bottom of the object which is using the brush. Additional the brush shall have a transparent margin, so the repeated Images shall not "touch" the container's border.
Currently I'm able to repeat an image x- and y-axis (and there I'm stuck ...). That for I use the following XAML:
<ImageBrush
x:Key="MandatoryIndicator"
ImageSource="image.png"
Stretch="None"
TileMode="Tile"
ViewportUnits="Absolute"
Viewport="0,0,16,16"
AlignmentY="Bottom"/>
And it Looks like this:
And I like to have it like this:
If you know how I have to modify my brush XAML, that would be great c[~] =)
You may use a VisualBrush with two nested elements like shown below. The outer Border (or some other outer element) is necessary for the transparent margin.
<VisualBrush Stretch="None" AlignmentX="Left" AlignmentY="Bottom">
<VisualBrush.Visual>
<Border Background="Transparent"
Width="{Binding ActualWidth,
RelativeSource={RelativeSource AncestorType=FrameworkElement}}">
<Rectangle Margin="10" Height="16">
<Rectangle.Fill>
<ImageBrush ImageSource="image.png" TileMode="Tile"
Viewport="0,0,16,16" ViewportUnits="Absolute"/>
</Rectangle.Fill>
</Rectangle>
</Border>
</VisualBrush.Visual>
</VisualBrush>
I want to move a textblock from left to end of screen. I have done like below. It slides from right end to left. But for lengthy texts it is not showing all texts. How can I resolve this?
<Grid>
<Canvas Grid.Row="0" Background="Blue">
<Canvas.Clip>
<RectangleGeometry Rect="0, 0, 2000, 800" />
</Canvas.Clip>
<TextBlock Name="txtScrollingNotification" Foreground="White"
Text="aaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccddddddddddddddddddddddddddddddddddddddddddddddddddddddddeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffgggggggggggggggggggggggggggggggggggggg hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjkkkkkkkkkkkkkkkkkkkkkkklllllllllllllllllllllmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnnnnnnnnnnnnnnnnnnnnoooooooooooooooooooooooooooooooooooooopppppppppppppppppppppppppp" Canvas.Top="6" />
</Canvas>
<Grid.Resources>
<Storyboard x:Name="Storyboard1">
<DoubleAnimation
Storyboard.TargetName="txtScrollingNotification"
Storyboard.TargetProperty="(Canvas.Left)"
Duration="0:0:10" From="2000"
To="0"
RepeatBehavior="Forever" />
</Storyboard>
</Grid.Resources>
</Grid>
Are you able to see all the text before the animation? It could be that your element isn't wide enough to display all the text.
If you add text wrapping to your text box, the text will wrap at the end of the element so you can see these dimensions
<TextBlock
Name="txtScrollingNotification"
Foreground="White"
Width="2000"
TextWrapping="Wrap"
Text="long text"
Canvas.Top="6" />
Resolved the issue by setting From and To value of DoubleAnimation programmatically
private void LoadScrollingTextBlock()
{
Storyboard sb = new Storyboard();
DoubleAnimation doubleAnimation = new DoubleAnimation();
doubleAnimation.From = this.ActualWidth;
doubleAnimation.To = -txtScrollingNotification.ActualWidth;
doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(55)); // provide an appropriate duration
//marquee.(Canvas.LeftProperty, doubleAnimation);
Storyboard.SetTarget(doubleAnimation, txtScrollingNotification);
Windows.UI.Xaml.Media.Animation.Storyboard.SetTargetProperty(doubleAnimation, "(Canvas.Left)");
sb.Children.Add(doubleAnimation);
sb.Begin();
}
I try to understand how windows phone viewport control Bounds work.
So i can give
viewport.Bunds = new Rect(x,y,width, height);
but what that bound stand for is it a scrollable area in the viewport.
Can anyone give me a working simple example of it cause whenever i try to use this parameter i can't scroll in viewport whatsover
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="0,0,0,0">
<ViewportControl Name="tuzik" Bounds="0,0,300,400" Margin="66,117,20,41" >
<Canvas Name="canvas">
<Image Name="TestImage" Source="Assets\testimage.jpg"
HorizontalAlignment="Left" VerticalAlignment="Top"
Canvas.Left="-379" Canvas.Top="-769" Stretch="Fill" />
</Canvas>
</ViewportControl>
<Rectangle x:Name="rect" Width="300" Height="400" Margin="60,111,63,0" Stroke="Aqua" />
</Grid>
I believe your problem is the Canvas within the ViewportControl. Canvas does not expand to fill the ViewportControl and will not expand to contain the contents, either. You have to set a Width and Height on the Canvas.
(At least, that's how I have mine setup.)
Both VariableSizedWrapGrid and WrapGrid have strange measuring - they measure all children based on the first item.
Because of that, the following XAML will clip the third item.
<VariableSizedWrapGrid Orientation="Horizontal">
<Rectangle Width="50" Height="100" Margin="5" Fill="Blue" />
<Rectangle Width="50" Height="50" Margin="5" Fill="Red" />
<Rectangle Width="50" Height="150" Margin="5" Fill="Green" />
<Rectangle Width="50" Height="50" Margin="5" Fill="Red" />
<Rectangle Width="50" Height="100" Margin="5" Fill="Red" />
</VariableSizedWrapGrid>
Seems like VariableSizedWrapGrid measures the first item and then the rest children are measured with desired size of the first one.
Any workarounds?
You need to use the Attached Properties on each Rectangle VariableSizeWrapGrid.ColumnSpan and VariableSizeWrapGrid.RowSpan as well as add an ItemHeight and ItemWidth to the VariableSizeWrapGrid:
<VariableSizedWrapGrid Orientation="Horizontal" ItemHeight="50" ItemWidth="50">
<Rectangle
VariableSizedWrapGrid.ColumnSpan="1"
VariableSizedWrapGrid.RowSpan="2"
Width="50" Height="100" Margin="5" Fill="Blue" />
</VariableSizedWrapGrid>
Its may be not the best way but this is how I have done this in my #MetroRSSReader app
<common:VariableGridView.ItemsPanel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid ItemWidth="225"
ItemHeight="{Binding ElementName=bounds, Path=Text}"
MaximumRowsOrColumns="5" Orientation="Vertical"
/>
</ItemsPanelTemplate>
</common:VariableGridView.ItemsPanel>
</common:VariableGridView>
Notice the ItemHeight value is bound to a TextBlock
<TextBlock x:Name="bounds" Grid.Row="1" Margin="316,8,0,33" Visibility="Collapsed"/>
Which is set in the LayoutAwarePage.cs
public string Fix_item_height_for_current_screen_resolution()
{
var screenheight = CoreWindow.GetForCurrentThread().Bounds.Height;
var itemHeight = screenheight < 1000 ? "100" : "140";
return itemHeight;
}
You can browse the full source code http://metrorssreader.codeplex.com/SourceControl/changeset/view/18233#265970
To use a VariableSizeWrapGrid you should create your own GridView custom control and override PrepareContainerForItemOverride and set the elements RowSpan and ColumnSpan inside that method. That way each element will have its own height/width.
Here is a nice tutorial/walk through by Jerry Nixon : http://dotnet.dzone.com/articles/windows-8-beauty-tip-using
Managed to figure this one out today. You'll need to make use of VisualTreeHelperExtension.cs in the WinRT XAML Toolkit (http://winrtxamltoolkit.codeplex.com). For me I was trying to adjust a ListView that had a GridView as its ItemsPanelTemplate, the same concept should apply for you.
1) Attach to the LayoutUpdated event of your ListView (this is when you'll want to update the sizes)
_myList.LayoutUpdated += _myList_LayoutUpdated;
2) Use VisualTreeHelperExtensions.GetDescendantsOfType() to find a common (and unique) element type in your item's data template (ex: a TextBlock that is dynamic in width):
var items = VisualTreeHelperExtensions.GetDescendantsOfType<TextBlock>(_myList);
if (items == null || items.Count() == 0)
return;
3) Get the max width of the items found:
double maxWidth = items.Max(i => i.ActualWidth) + 8;
4) Use VisualTreeHelperExtensions.GetDescendantsOfType() to find the main WrapGrid container for your ListView:
var wg = _categoryList.GetDescendantsOfType<WrapGrid>();
if (wg == null || wg.Count() != 1)
throw new InvalidOperationException("Couldn't find main ListView container");
5) Set the WrapGrid's ItemWidth to the maxWidth you calculated:
wg.First().ItemWidth = maxWidth;