Button with image not overlaying another image - c#

I have an image that is the stretched to be the size of the window (width and height wise).
I have a button that sits on top with the following XAML:
<Image Source="sample.png"></Image>
<Button Height="50" Width="100" Content="OverLay Image" Foreground="AliceBlue"
Background="Transparent" HorizontalAlignment="Left"
VerticalAlignment="Top"/>
This shows the button fine when I run, however, I'd like the button to have an image instead of text using this template:
<Button Height="50" Width="100" Content="OverLay Image"
Foreground="AliceBlue" Background="Transparent"
HorizontalAlignment="Left" VerticalAlignment="Top">
<Button.Template>
<ControlTemplate>
<Border>
<Image Source="img/sample.png"
Width="32"
Height="32"/>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
When I add the template section:
<Button.Template>
<ControlTemplate>
<Border>
<Image Source="img/sample.png"
Width="32"
Height="32"/>
</Border>
</ControlTemplate>
</Button.Template>
The button disappears. Has anyone seen this before or know how to force the button to show?
Thanks in advance!

It could be nothing, but I noticed that in your first (working) example of the Image, you used this path to your image:
<Image Source="sample.png"></Image>
But the one that you say doesn't work is using this path:
<Image Source="img/sample.png"/>
Maybe that was just an error you made copying it here, but otherwise, try this in your ControlTemplate:
<Image Source="sample.png"/>

Since you've changed the ControlTemplate it will only show your image. Everything looks fine, are you sure that the image path is correct? Try setting the background of the border to make sure that there isn't anything wrong with your template. Use Snoop to get look at the VisualTree and look at the source of the image.

Related

How to Fill SolidColorBrush/Ellipse [duplicate]

I am trying to create this in WPF (I realize I could just use an image, but I am trying to learn WPF):
(source)
This is what I have so far but it isn't producing the desired result, in that, the textbox seems completely hide the ellipse whereas it should simply have a transparent background:
<StackPanel>
<TextBlock HorizontalAlignment="Left" Margin="144,207,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top"/>
<Ellipse HorizontalAlignment="Left" Height="52" Margin="142,189,0,0" Stroke="Black" VerticalAlignment="Top" Width="52"/>
</StackPanel>
You can put things like this in a viewbox to make scaling easier, something like this. You'll need to remove the stack panel, it's going to stack items one on top of the other which isn't what you're after here. I used a grid in this case.
<Viewbox Width="100" Height="100">
<Grid Width="20" Height="20">
<Ellipse Stroke="Black"/>
<TextBlock HorizontalAlignment="Center" Text="i" TextAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Viewbox>
Or you can use the unicode character: ⓘ
code 0x24D8
<TextBlock Text="ⓘ" FontSize="52" />
So a stackpanel will place the first item at the top, the second just below it, third below the second, and so forth. What you could do is use a Canvas or a Grid. Like the stackpanel, they are "Content Controls" and support placing multiple objects inside of them like you have done with the stackpanel.
So a really quick way to do what you're trying to accomplish would be:
<Grid >
<Ellipse HorizontalAlignment="Left" Height="52" Stroke="Black" VerticalAlignment="Top" Width="52"/>
<TextBlock Text="i" FontSize="52" Margin="18,-13,-6,13" />
</Grid>
You can do it using a border and a TextBlock. A square border will become a circle if you make its CornerRadius equals half its Width (or Height):
<Border Width="100" Height="100" CornerRadius="50" BorderBrush="Black" BorderThickness="2">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"
FontSize="50" Foreground="Blue" >i</TextBlock>
</Border>
Don't use a StackPanel for this, the purpose of it is to stack things, not show them overlapped, you're using the wrong tool for that. Use a Grid, it's far more suited for what you're trying to do.
To have a transparent background, you have to either set the TextBlock's Background property to Transparent, or set a null background.
Background={x:Null}

Blur images no matter what in WPF

I have a button with an image and no matter what I do the image looks blurry after rendered/compiled.
FYI - The image looks good when not in WPF controls
The image on the left is before compiled, the image on the right is blurry after compiled.
I tried applying UseLayoutRounding, applying SnapsToDevicePixels,
RenderOptions.BitmapScalingMode and removing the antialiasing directly in the button and directly to the image but nothing.
Any idea how can I improve the quality of the images in WPF?
XAML:
Styles applied directly to the button:
<Grid>
<Button x:Name="recentButton" UseLayoutRounding="True" RenderOptions.BitmapScalingMode="HighQuality" SnapsToDevicePixels="True" RenderOptions.EdgeMode="Aliased"
Margin="10,137,302,10"
Width="auto"
Height="23"
HorizontalAlignment="Stretch"
BorderBrush="{x:Null}"
Foreground="White"
BorderThickness="0"
Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
<Image Source="/Tool;component/Design/Images/more-icon-active.png" Stretch="None"/>
</Button>
</Grid>
Styles applied directly to the image:
<Grid>
<Button x:Name="recentButton"
Margin="10,137,302,10"
Width="auto"
Height="23"
HorizontalAlignment="Stretch"
BorderBrush="{x:Null}"
Foreground="White"
BorderThickness="0"
Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
<Image Source="/Tool;component/Design/Images/more-icon-active.png" UseLayoutRounding="True" RenderOptions.BitmapScalingMode="HighQuality" SnapsToDevicePixels="True" RenderOptions.EdgeMode="Aliased" Stretch="None"/>
</Button>
</Grid>
The problem is you're using UseLayoutRounding on the control directly.
But, be aware of this note in the linked documentation,
You should set UseLayoutRounding to true on the root element. The layout system adds child coordinates to the parent coordinates; therefore, if the parent coordinates are not on a pixel boundary, the child coordinates are also not on a pixel boundary. If UseLayoutRounding cannot be set at the root, set SnapsToDevicePixels on the child to obtain the effect that you want.
Therefore, use it on the parent container instead. In your case, that would be on the on the <grid> element.
Other recommandations
Recommended by #Clemens in the comment section,
Depending on the kind of image, RenderOptions.BitmapScalingMode="NearestNeighbor" may add some sharpness.
Note that you will have to apply that on the image directly.
Recommended by #BradleyUffner in the comment section,
Setting TextOptions.TextFormattingMode="Display" on your top level elements to greatly improve text rendering on desktop computers.

WPF How to make a Viewbox aware of its available space from within a StackPanel

I have a custom WPF control based on Soroosh Davaee’s ImageButton example at http://www.codeproject.com/Tips/773386/WPF-ImageButton. The custom control combines an Image and TextBlock in a horizontal StackPanel within a Button. (BTW, to get Soroosh’s example to run, I had to edit the solution properties so that “SampleView” is the startup project rather than “ExtendedButton” being the startup project.)
I want the text in the TextBlock to automatically shrink if necessary to avoid clipping at the right edge if the text is too long to fit naturally in the button. For example, if I edit Soroosh's MainWindow.xaml to make the button text too long to fit...
...
<EB:ImageButton Width="100" Height="30" Content="TextTooLongToFitInTheButton" Grid.Row="2"
...
<EB:ImageButton Width="100" Height="30" Content="TextTooLongToFitInTheButton" Grid.Row="2"
...
...the result is the following buttons with clipped text:
In researching this, it seems the simplest way to auto-shrink the content of a TextBlock is to wrap it within a Viewbox:
<Viewbox StretchDirection="DownOnly" Stretch="Fill">
<TextBlock ... />
</Viewbox>
DownOnly apparently prevents the Viewbox from enlarging the text to fill the space, and Fill (as opposed to Uniform) seems to tell it to stretch (shrink) only the dimension that needs to shrink (i.e. the horizontal dimension in my case).
In Soroosh's example Generic.xaml file, I wrapped the TextBlock in such a Viewbox:
<Button >
<StackPanel Orientation="Horizontal">
<Image Margin="2 0"
Source="{TemplateBinding Image}"
Width="{TemplateBinding ImageWidth}"
Height="{TemplateBinding ImageHeight}"
Visibility="{TemplateBinding Image,Converter={StaticResource VisibilityConvertor}}"
VerticalAlignment="Center"/>
I added--> <Viewbox StretchDirection="DownOnly" Stretch="Fill">
<TextBlock Text="{TemplateBinding Content}"
VerticalAlignment="Center"/>
I added--> </Viewbox>
</StackPanel>
</Button>
This produced exactly the same clipped button text. Just experimenting, I tried forcing the Viewbox to have a fixed width...
<Viewbox StretchDirection="DownOnly" Stretch="Fill" Width="60">
...which produced this:
...which shows the capability of the Viewbox, if only it could somehow know its available width when it's inside the StackPanel.
I did note that if I wrap the Viewbox around the whole StackPanel, it successfully auto-shrinks the entire content of the StackPanel:
<Button >
<Viewbox StretchDirection="DownOnly" Stretch="Fill" Width="60">
<StackPanel Orientation="Horizontal">
<Image Margin="2 0"
Source="{TemplateBinding Image}"
Width="{TemplateBinding ImageWidth}"
Height="{TemplateBinding ImageHeight}"
Visibility="{TemplateBinding Image,Converter={StaticResource VisibilityConvertor}}"
VerticalAlignment="Center"/>
<TextBlock Text="{TemplateBinding Content}"
VerticalAlignment="Center"/>
</StackPanel>
</Viewbox>
</Button>
...which produces very nearly what I want:
...but both the image and text are shrunk, and I want only the text shrunk.
How can I make the Viewbox, wrapping only the TextBox, know its available width (and height, I suppose) from within a cell of the StackPanel?
This is a common problem. The solution is simply to not use a StackPanel to do any kind of layout that requires re-sizing of child controls. It's simply not the correct Panel for the job. Instead, try using a Grid panel, which will resize its child controls. The StackPanel control is really only good for the most basic of layout duties... try anything more adventurous and you'll find yourself getting these issues.
One other alternative is to use the TextBlock.TextTrimming Property to trim the text instead... you could put the full text into a ToolTip too.

Windows 8 WinRT Xaml Grid inside InlineUIContainer

In my Windows 8 ItemDetail view, I want to add an overlay image to the standard image which is contained inside an InlineUIContainer element.
This is the xaml I am using:
<Paragraph LineStackingStrategy="MaxHeight">
<InlineUIContainer>
<Grid x:Name="MediaGrid" Width="560" Height="315" Margin="0,20,0,10">
<Grid.Background>
<ImageBrush ImageSource="{Binding Image}" Stretch="UniformToFill" />
</Grid.Background>
<Button Click="Button_Click" Background="Transparent" BorderBrush="Transparent" BorderThickness="0">
<Button.Template>
<ControlTemplate TargetType="Button">
<Image x:Name="OverlayImage" Visibility="{Binding ShowVideo, Converter={StaticResource booleanToVisibilityConverter}}" Source="ms-appx:///Assets/play-icon.png"/>
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</InlineUIContainer>
</Paragraph>
This works perfectly when the app is in landscape mode. However as soon as I rotate, or open the app in portrait mode I receive the error:
WinRT information: Cannot resolve TargetName image. Additional information: Unspecified error in LayoutAwarePage.cs VisualStateManager.GoToState(control, DetermineVisualState(ApplicationView.Value), false);
Does anyone have any idea why? After a little process of elimination, it seems to happen when I have a Grid inside the InlineUIContainer.
Looks like a control name 'image' is missing and is only triggered when the VisualState is changed

Rendering buttons on top of MediaElement in WPF

I have a MediaElement object in my XAML, which loads my movie just fine. What I want to do is render the play, pause and stop buttons right in the center my MediaElement object, kind of like how if you embed a YouTube video on a web page, you get the big play button in the center of the video. Can I do this in WPF using MediaElement?
In case anyone else ever needs to do this, I figured it out. I simply created a Canvas and stuck the MediaElement and the Button both inside the Canvas. I then used ZIndex to change the ZOrdering so the button was on top. Finally, I centered the button on top of my movie. Here is the XAML:
<StackPanel Orientation="Horizontal" Background="LightGray" DockPanel.Dock="Bottom" Height="100">
<Canvas Width="100">
<Button Canvas.ZIndex="2" Canvas.Left="42" Canvas.Top="35">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Polygon Points="0,0 0,26 17,13" Fill="#80000000" Stroke="White" />
</ControlTemplate>
</Button.Template>
</Button>
<MediaElement Canvas.ZIndex="1" Canvas.Top="0" Canvas.Left="0"
x:Name="mediaElement1" UnloadedBehavior="Manual" LoadedBehavior="Manual" ScrubbingEnabled="True"
Loaded="mediaElement1_Loaded" Width="100" Height="100">
</MediaElement>
</Canvas>
</StackPanel>
Or you need to place mediaElement and Buttons to same Grid and set Canvas.ZIndex to higher number than 0:
<Grid>
<Button VerticalAlignment="Center" HorizontalAlignment="Center" Height="50" Width="100" Canvas.ZIndex="1">Button</Button>
<MediaElement Source="/Assets/ladybug.wmv">
</MediaElement>
</Grid>
(actually you don't need Canvas [works on UWP]):

Categories