Unknown HyperlinkButton margin/padding with style/template - c#

I'm trying to do the html to xaml convertor and use this code as a starting point. My app is Windows Phone 8.1 universal app. This code works very good except the hyperlinks. It looks like HyperlingButton have some hidden margin or padding and I can't fix it in the style by setting it to 0.
The hyperlink is marked with red border:
My style is here:
<Style TargetType="HyperlinkButton" x:Key="UnderlineHyperlinkButton">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Margin" Value="0,0,0,0" />
<Setter Property="Padding" Value="0,0,0,0"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="FontFamily" Value="{ThemeResource PhoneFontFamilyNormal}"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="HyperlinkButton">
<TextBlock Style="{StaticResource TextStylePostBody}">
<Underline>
<Run Text="{Binding Path=Content, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
</Underline>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Style for TextBlock:
<Style x:Key="TextStylePostBody" TargetType="TextBlock" BasedOn="{StaticResource BaseTextBlockStyle}">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="Padding" Value="0,0,0,0"/>
<Setter Property="Margin" Value="0,0,0,0"/>
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="TextTrimming" Value="WordEllipsis"/>
<Setter Property="TextWrapping" Value="WrapWholeWords"/>
</Style>
I can fix it with hardcoded values in margin <Setter Property="Margin" Value="0,-9, 4,-4"/> but it does not looks good.
The code that creates hyperlink is here:
private static Inline GenerateHyperLink(HtmlNode node)
{
Span s = new Span();
InlineUIContainer iui = new InlineUIContainer();
HyperlinkButton hb = new HyperlinkButton() { NavigateUri = new Uri(node.Attributes["href"].Value, UriKind.Absolute), Content = CleanText(node.InnerText) };
hb.Style = ( Style )Application.Current.Resources[ "UnderlineHyperlinkButton" ];
iui.Child = hb;
s.Inlines.Add(iui);
return s;
}
Is there something that I missed?
Update:
Did a quick test with this XAMl code:
<StackPanel Grid.Row="0" Orientation="Horizontal">
<TextBlock Foreground="Black" FontSize="18" FontWeight="Normal" FontFamily="Segroe UI">TextBlock</TextBlock>
<RichTextBlock>
<Paragraph>
<Run Foreground="Black" FontSize="18" FontWeight="Normal" FontFamily="Segroe UI">
<Run.Text>Run text</Run.Text>
</Run>
<InlineUIContainer>
<HyperlinkButton FontSize="18" FontFamily="Segroe UI" FontWeight="Normal" Margin="0" Padding="0,0,0,0">Link Text</HyperlinkButton>
</InlineUIContainer>
</Paragraph>
</RichTextBlock>
</StackPanel>
and got this:
Setting Margin of HyperlinkButton to -9 (Top):
It's not the problem of other text or InlineUIContainer, replacing HyperlinkButton with TextBlock fixes the margins:

Decided to avoid InlineUIContainer and HyperlinkButton due to align and formatting problems. I have replaced it with <Underline> with Link attached property. More info in this article.
EDIT: Don't know why, but I missed that runtime API have a dedicated Hyperlink class that do the job very well.

Related

How to set one content to several buttons in WPF

I have some buttons -in different windows- that have the same content. But if two windows surfaced together,out of the first window's button content disappears.
Buttons Style is :
<Style TargetType="{x:Type Button}" x:Key="BSaveBtn">
<Setter Property="Padding" Value="5"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Width" Value="70"/>
<Setter Property="Height" Value="68"/>
<Setter Property="Background" Value="{DynamicResource FlatGreen}"/>
<Setter Property="Template" Value="{DynamicResource FlatGreenBtnHover}"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="Content">
<Setter.Value>
<StackPanel Orientation="Vertical" FlowDirection="RightToLeft">
<Image Width="30" Source="/login;component/img/buttonpic/save.png"/>
<TextBlock Text="save" FontSize="16" FontFamily="/login;component/fonts/#Droid Arabic Kufi" Foreground="White" HorizontalAlignment="Center"/>
</StackPanel>
</Setter.Value>
</Setter>
</Style>
button Code in windows is :
<Button Style="{DynamicResource BSaveBtn}" Template="{DynamicResource FlatGreenBtnHover}" />
problems occurs only with content -not another style properties- .
Seems to work fine for me when I tested it here.
A few things I noticed though that may help. You don't need them to be DynamicResource, they should really be StaticResource unless you plan on modifying them.
I assume you are declaring these in the Windows.Resource section or repeating them on each window?
If so you should centralize those to a ResourceDictionary.
Create a new Resource Dictionary put your style in there like so:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="{x:Type Button}" x:Key="BSaveBtn">
<Setter Property="Padding" Value="5"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Width" Value="70"/>
<Setter Property="Height" Value="68"/>
<Setter Property="Background" Value="{DynamicResource FlatGreen}"/>
<Setter Property="Template" Value="{DynamicResource FlatGreenBtnHover}"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="Content">
<Setter.Value>
<StackPanel Orientation="Vertical" FlowDirection="RightToLeft">
<Image Width="30" Source="/login;component/img/buttonpic/save.png"/>
<TextBlock Text="save" FontSize="16" FontFamily="/login;component/fonts/#Droid Arabic Kufi" Foreground="White" HorizontalAlignment="Center"/>
</StackPanel>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Then in your App.xaml put the following:
<ResourceDictionary>
<ResourceDictionary Source="MyResources.xaml" />
</ResourceDictionary>
The Image should really be in a dictionary to avoid loading it multiple times. Just add a line in that ResourceDictionary like so:
<BitmapImage UriSource="/login;component/Images/Save.png" x:Key="Save" PresentationOptions:Freeze="True" />
Setting the PresentationOptions:Freeze will also help if the image is never being modified.
Your call to the image would then change to be:
<StackPanel Orientation="Vertical" FlowDirection="RightToLeft">
<Image Width="30" Source="{StaticResource Save}"/>
<TextBlock Text="save" FontSize="16" FontFamily="/login;component/fonts/#Droid Arabic Kufi" Foreground="White" HorizontalAlignment="Center"/>
</StackPanel>
Once your resources are centralized in a ResourceDictionary (or multiple) it makes it easy to apply those same styles anywhere in your application and hopefully will help with your issue. If not please give more info on the problem you have such as sample code to make the issue happen please.
An instance of an element can only appear once in the visual tree. You can set the x:Shared attribute of the Style to False in order for a new instance of the StackPanel to get created for each Button to which you apply the style:
<Style TargetType="{x:Type Button}" x:Key="BSaveBtn" x:Shared="False">
<Setter Property="Padding" Value="5"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Width" Value="70"/>
<Setter Property="Height" Value="68"/>
<Setter Property="Background" Value="{DynamicResource FlatGreen}"/>
<Setter Property="Template" Value="{DynamicResource FlatGreenBtnHover}"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="Content">
<Setter.Value>
<StackPanel Orientation="Vertical" FlowDirection="RightToLeft">
<Image Width="30" Source="/login;component/img/buttonpic/save.png"/>
<TextBlock Text="save" FontSize="16" FontFamily="/login;component/fonts/#Droid Arabic Kufi" Foreground="White" HorizontalAlignment="Center"/>
</StackPanel>
</Setter.Value>
</Setter>
</Style>

Create Border-Style with integrated TextBox

I have to work with a 1800-Row-XAML-Definition for a single window and I want to reduce the amount of code drastically.
There are several control-definitions, which are repeated very often and I want to write Styles for some of them. One example is a Border-Definition with integrated TextBox:
<Border Grid.Column="2" Margin="1,1,5,0" Background="#bbc2ce">
<my:RibbonTextBox HorizontalContentAlignment="Center"
IsReadOnly="True" Background="#FAFAFA"
Text="{Binding Path=someViewModel.Item,Mode=OneWay}"
MinHeight="0" FontSize="12" FontWeight="Bold" FontFamily="Arial"/>
</Border>
Apart of the Binding Path, every value is exact the same over and over again. So I wrote this Style for the RibbonTextBox:
<Style TargetType="my:RibbonTextBox" x:Key="StandardRibbonTextBox">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="Background" Value="#FAFAFA" />
<Setter Property="MinHeight" Value="0" />
<Setter Property="FontSize" Value="12" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="FontFamily" Value="Arial" />
</Style>
Now I want to write a style for above border, and integrate the RibbonTextBox Style. Here I am so far:
<Style TargetType="Border" x:Key="borderStyle">
<Setter Property="Background" Value="#bbc2ce" />
</Style>
Is there a possibility to integrate my TextBox-Style here? And if not, does somebody know, how to resolve this issue?
Thanks in advance!
If you only need the readonly textbox, you can use DataTemplate with ContentPresenter as coded below (replaced my:RibbonTextBox with simple TextBox for demonstration). If you need read-write, you have to provide some way of binding that allows read-write. This can be achieved with ControlTemplate (also in sample code).
<Grid x:Name="grid1">
<Grid.Resources>
<Style TargetType="TextBox" x:Key="StandardRibbonTextBox">
<!--Changed that one from HorizontalAlignment, in comparison to the question-->
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="Background" Value="#FAFAFA" />
<Setter Property="MinHeight" Value="0" />
<Setter Property="FontSize" Value="12" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="FontFamily" Value="Arial" />
</Style>
<Style TargetType="Border" x:Key="borderStyle">
<Setter Property="Background" Value="#bbc2ce" />
<Setter Property="Margin" Value="1,1,5,0"/>
<Setter Property="Padding" Value="5"/>
</Style>
<DataTemplate x:Key="borderedTextboxTemplate" DataType="{x:Type sys:String}">
<Border Style="{StaticResource borderStyle}">
<!--This is not going to work for two way binding (IsReadOnly="False" and Text="{Binding Mode=TwoWay}")-->
<TextBox Style="{StaticResource StandardRibbonTextBox}" Text="{Binding Mode=OneWay}"/>
</Border>
</DataTemplate>
<ControlTemplate x:Key="borderedTextboxControlTemplate" TargetType="TextBox">
<Border Style="{StaticResource borderStyle}">
<!--This is not going to work for two way binding (IsReadOnly="False" and Text="{Binding Mode=TwoWay}")-->
<TextBox Style="{StaticResource StandardRibbonTextBox}" Text="{Binding Text,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"/>
</Border>
</ControlTemplate>
<Style x:Key="borderedTextboxControlStyle" TargetType="TextBox">
<Setter Property="Template" Value="{StaticResource borderedTextboxControlTemplate}"/>
</Style>
</Grid.Resources>
<StackPanel Margin="10">
<!--Using Controls directly-->
<Border Style="{StaticResource borderStyle}">
<TextBox
Text="{Binding Path=someViewModel.Item,Mode=OneWay}"
Style="{StaticResource StandardRibbonTextBox}"/>
</Border>
<Separator Margin="10"/>
<!--Using DataTemplate-->
<ContentPresenter
Content="{Binding Path=someViewModel.Item,Mode=OneWay}"
ContentTemplate="{StaticResource borderedTextboxTemplate}"/>
<Separator Margin="10"/>
<!--Using ControlTemplate via Style-->
<TextBox Text="{Binding Path=someViewModel.Item,Mode=OneWay}" Style="{StaticResource borderedTextboxControlStyle}"/>
</StackPanel>
</Grid>

How to style TextBox Header?

I am using a TextBox like this:
<TextBox x:Name="TxtName" IsEnabled="False" Header="Textbox header" IsReadOnly="True" TextWrapping="Wrap" Text="{Binding Name,Mode=TwoWay}" Style="{StaticResource MyTextBoxStyle}" />
I would like to be able to style (i.e. setting the font) the Header of the TextBox in a ResourceDictionary. When I set the FontFamily of the TextBox it also affect the header, but I would like to set two different font styles for the text inside the TextBox and the text in the Header.
This is my style for the TextBox:
<Style x:Key="MyTextBoxStyle" TargetType="TextBox">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="FontFamily" Value="Comic Sans MS" />
</Style>
How can I do this?
Try This
<TextBox Height="70" Width="200" Text="Text" Foreground="Green" FontFamily="Tahoma">
<TextBox.Header>
<TextBlock Text="Header" Foreground="red" FontFamily="Times New Roman"></TextBlock>
</TextBox.Header>
</TextBox>
Update
<Page.Resources>
<Style TargetType="TextBox">
<Setter Property="Height" Value="70"></Setter>
<Setter Property="Width" Value="200"></Setter>
<Setter Property="Text" Value="Text"></Setter>
<Setter Property="FontFamily" Value="Tahoma"></Setter>
<Setter Property="Foreground" Value="Green"></Setter>
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Foreground="Red" Text="{Binding}" FontFamily="Times New Roman"></TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<TextBox Header="Header" />

Change OnClick label color WPF

Im coming from a C# winforms background and I would normally do all this in code.
I have several Labels that I'm using as a menu.
When the mouse hovers over them the text changes color by:
<Page.Resources>
<SolidColorBrush x:Key="normalColor" Color="White" />
<SolidColorBrush x:Key="mouseOverColor" Color="Gold" />
<Style TargetType="Label" x:Key="menuItemStyle">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Foreground" Value="{StaticResource normalColor}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="{StaticResource mouseOverColor}"/>
</Trigger>
</Style.Triggers>
</Style>
</Page.Resources>
<Label x:Name="Label_Video1" Style="{StaticResource menuItemStyle}" Content="1.Video 1." FontSize="16" HorizontalAlignment="Left" Margin="25,74,0,0" VerticalAlignment="Top" MouseLeftButtonDown="Label_Video1_MouseLeftButtonDown" />
<Label x:Name="Label_Video2" Style="{StaticResource menuItemStyle}" Content="2. Video 2." FontSize="16" HorizontalAlignment="Left" Margin="25,105,0,0" VerticalAlignment="Top" MouseDown="Label_Video2_MouseDown"/>
When the user clicks a label I want it to stay a certin color (In this case Gold) and all the others to stay their normal colour. So if a label has been previously clicked and I click another label it will go from gold to white etc
When using WPF, you have to think slightly differently. We know that the Label control doesn't know when it has been clicked and it especially doesn't know when another Label element has been clicked... but some controls do. Thinking about it... a RadioButton has exactly this behaviour. Now this is where WPF really shines.
We can use RadioButtons and by providing them with a new ControlTemplate, we can make them look like plain text:
<Grid Background="Black">
<Grid.Resources>
<Style TargetType="{x:Type RadioButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RadioButton}">
<TextBlock Text="{TemplateBinding Content}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, RelativeSource={RelativeSource AncestorType={
x:Type RadioButton}}}" Value="True">
<Setter Property="Foreground" Value="Gold" />
</DataTrigger>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource
AncestorType={x:Type RadioButton}}}" Value="True">
<Setter Property="Foreground" Value="Gold" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<StackPanel Margin="5" Background="{x:Null}">
<RadioButton Content="1.Video 1." />
<RadioButton Content="2.Video 2." />
<RadioButton Content="3.Video 3." />
</StackPanel>
</Grid>
If you don't want the RadioButtons to be all together in a StackPanel, then you can use give them the same GroupName property value to ensure that they still operate as one group.

How to Call the Style function for button in wpf?

I have created button style in wpf form
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<Button Background="Blue" FontStyle="Normal"
Padding="8,4" Margin="4" Foreground="White" FontWeight="Bold" Click="Button_Click">Prabhu
</Button>
</StackPanel>
I need to call this same style in 10 buttons. how to call the same style in all buttons?
use the resources of whateve rtop level element you want to use:
<StackPanel>
<StackPanel.Resources>
<Style TargetType="Button" x:Key="ButtonStyle">
<Setter Property="Background" Value="Blue"></Setter>
<Setter Property="FontStyle" Value="Normal"></Setter>
<Setter Property="Padding" Value="8,4"></Setter>
<Setter Property="Margin" Value="4"></Setter>
<Setter Property="Foreground" Value="White"></Setter>
<Setter Property="FontWeight" Value="Bold"></Setter>
</Style>
</StackPanel.Resources>
<Button>Default Styled Button</Button>
<Button Style="{StaticResource ButtonStyle}">Fancy Blue Button</Button>
</StackPanel>
if this is going to be a global style, or you want it accessible in your entire application, i recommend creating a resource dictionary and putting it in there. then in your app.xaml, reference the resource dictionary. this article goes more in depth on that topic

Categories

Resources