Semitransparent background and opaque foreground wpf - c#

I currently have the following xaml code:
<Grid
Name="rootGrid"
Opacity=".25"
Background="Black"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Border
Background="Black"
Margin="120">
<Grid
Background="White"
Margin="8">
<TextBlock
Name="popupContent">
Test
</TextBlock>
<Button
Click="Button_Click">
Test
</Button>
</Grid>
</Border>
</Grid>
Currently, the Opacity setting on the Grid is also applied on its children.
I only want this opacity to be applied on its background color, to achieve a darkening effect, not on the foreground. How can I do this?

Use a semi-transparent background, either as a SolidColorBrush like
<Grid ...>
<Grid.Background>
<SolidColorBrush Color="Black" Opacity="0.25"/>
</Grid.Background>
...
</Grid>
or by specifying an alpha value in the color, like
<Grid Background="#3F000000" ...>

The trick is to not add the Opacity to the entire Grid element:
<Grid>
<Grid.Background>
<SolidColorBrush Color="Black" Opacity=".75"/>
</Grid.Background>
<!--(Other elements)-->
</Grid>

This worked for me. I have two Grids a Root grid and RootContent sub-grid. I control the Opacity of the RootContent. Any controls in the "Root" will not be effected.
<Grid x:Name="Root" KeyDown="Root_KeyDown" Tapped="Root_Tapped">
<!--(Other elements)-->
<Grid x:Name="RootContent">
<!--(Other elements)-->
</Grid>
</Grid>

The opacity will always apply to children, so I tend to use a Canvas at the same level to achieve this affect:
<Grid>
<Canvas Opacity=".25"
Background="Black"/>
<Grid Name="rootGrid"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Border
Background="Black"
Margin="120">
<Grid
Background="White"
Margin="8">
<TextBlock
Name="popupContent">
Test
</TextBlock>
<Button
Click="Button_Click">
Test
</Button>
</Grid>
</Border>
</Grid>
</Grid>

Related

Display icon over select images in wpf listbox

I've looked at some related answers (Content of a Button Style appears only in one Button instance, and Images only showing in last ListBoxItem), but can't seem to get their answers to work in my example.
My app wpf stack is relatively complex.
I've a UserControl within another window. Within the UserControl, I've a ListBox with nested elements ListBox.ItemTemplate > DataTemplate > Border > Grid > StackPanel
Within the StackPanel is a TextBlock, followed by an Image and a StackPanel.ToolTip
I'm wanting to place an icon over the Image, so I've further obfuscated the image by putting it in a Grid, and adding a ViewBox accessed via a Control Template (as suggested in the above links), so that the ViewBox is centered on the image. Here's the Grid:
<Grid>
<Image RenderOptions.BitmapScalingMode="HighQuality"
Height="{Binding ElementName=_this, Path=ThumbSize.Height}"
>
<gif:ImageBehavior.AnimatedSource>
<MultiBinding Converter="{c:ImageConverter}">
<Binding Path="ThumbLocation" />
<Binding Path="FullName" />
</MultiBinding>
</gif:ImageBehavior.AnimatedSource>
</Image>
<Control Template="{StaticResource PlaySymbol}" Visibility="{Binding PlayVisible}" />
</Grid>
The ViewBox's ControlTemplate is in the UserControl.Resources up at the top
<ControlTemplate x:Key="PlaySymbol" TargetType="{x:Type Control}">
<Viewbox Stretch="Uniform"
RenderTransformOrigin="0.5,0.5"
Opacity="0.75"
x:Shared="False"
>
<Viewbox.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.5" ScaleY="0.5"/>
</TransformGroup>
</Viewbox.RenderTransform>
<ContentControl Content="{StaticResource appbar_control_play}" />
</Viewbox>
</ControlTemplate>
The appbar_control_play is in the Resources directory in an Icons.xaml file.
<Canvas x:Key="appbar_control_play" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
<Path Width="20.5832" Height="31.6667" Canvas.Left="30.0833" Canvas.Top="22.1667" Stretch="Fill" Fill="{DynamicResource BlackBrush}" Data="F1 M 30.0833,22.1667L 50.6665,37.6043L 50.6665,38.7918L 30.0833,53.8333L 30.0833,22.1667 Z "/>
</Canvas>
The goal is to only display the icon for 'play' on movies. I've set the PlayVisible to return the proper visibility for movies, and not for other files. Yet, it is only displaying for the last movie. I've heard that this is the case for controls only able to have one parent. I've tried setting x:Shared="False" on the ViewBox, but to no avail.
The app works, but I've recently decided to add movies to the listing and want to display the play icon over their thumbnails, but not the other items. It seems simple on the outset, but I've yet to figure out what is needed.
Any help would be appreciated, otherwise I feel I may have to resort to overlaying the icon on the actual thumbnails of the movies.
It looks like the problem is not related to the Viewbox but the image resource appbar_control_play it references.
There is no need to add the Viewbox via a Control. Just add it directly to the DataTemplate.
Generally prefer a ContentControl over a templated Control if you wish to display content.
The x:Shared attribute is only required on a UIElement that is not part of a template but defined in a ResourceDictionary. For example, when you define the Viewbox in as a resource, you must set the x:Shared attribute to false. Otherwise it is only allowed to appear once in the visual tree.
In case the image resource is an image file, a proper DataTemplate could look as followed:
<DataTemplate>
<StackPanel>
<Grid>
<Image Source="path to image" />
<Image Source="path to overlay icon"
Stretch="UniformToFill"
Width="50"
Height="50" />
</Grid>
</StackPanel>
</DataTemplate>
In case the icon is a XAML resource like a Geometry or a Segoe MDL2 Assets font icon, the DataTemplate should look as followed:
App.xaml
<Application.Resources>
<Viewbox x:Key="PlayIcon" x:Shared="False">
<TextBlock FontFamily="Segoe MDL2 Assets"
Text="" />
</Viewbox>
<Viewbox x:Key="appbar_control_play"
x:Shared="False">
<Path Width="20.5832"
Height="31.6667"
Stretch="Fill"
Fill="{Binding RelativeSource={RelativeSource AncestroType=ContentControl}, Path=For4ground}"
Data="F1 M 30.0833,22.1667L 50.6665,37.6043L 50.6665,38.7918L 30.0833,53.8333L 30.0833,22.1667 Z " />
</Viewbox>
</Application.Resources>
MyControl.xaml
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Grid>
<Image Source="path to image" />
<ContentControl Content="{StaticResource appbar_control_play}"
Width="50"
Height="50"
Foreground="Pink" />
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
Not sure what's happening on your side but the following just works:
<Window x:Class="abc.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
mc:Ignorable="d"
Title="Window1">
<Grid>
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<DataTemplate.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</DataTemplate.Resources>
<Border Width="64" Height="64" BorderBrush="Red" BorderThickness="1">
<Grid>
<TextBlock Text="{Binding}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<Rectangle Fill="DeepSkyBlue"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Margin="2"
Width="16"
Height="16"
Visibility="{Binding Converter={StaticResource BooleanToVisibilityConverter}}"
x:Name="Button" />
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
<system:Boolean>True</system:Boolean>
<system:Boolean>False</system:Boolean>
<system:Boolean>True</system:Boolean>
<system:Boolean>False</system:Boolean>
<system:Boolean>True</system:Boolean>
<system:Boolean>False</system:Boolean>
</ListBox>
</Grid>
</Window>

How to bind command on entire Grid LeftClick in WPF User Control

I want to achieve Grid Left Click inside a user control.
My WPF User Control
<Grid>
<Border Grid.Row="0" CornerRadius="7" >
<Border.Background>
<SolidColorBrush Color="#ffffff" Opacity="0.08"></SolidColorBrush>
</Border.Background>
<Grid>
<Image Source="/Assets/Images/Icon/ic-add.png" Width="70" Height="70"/>
</Grid>
</Border>
</Grid>
Here is my Window
<Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<usercontrols:CreateNewProfile Width="200" Height="235" Margin="40,40,0,0">
</usercontrols:CreateNewProfile>
</<StackPanel>
</Grid>
There is a command Called CreateNewProfile
Very straight question How to bind command on Left Click of User Control?
You can use InputBindings inside of your UserControl:
<Grid.InputBindings>
<MouseBinding MouseAction="LeftClick" Command="{Binding CreateNewProfile}"/>
</Grid.InputBindings>

WPF - change text anchor in Canvas

Here's some XAML:
<Grid Width="200" Height="200">
<Canvas Background="Beige">
<Line X1="0" X2="200" Y1="100" Y2="100" Stroke="Black"/>
<Line X1="100" X2="100" Y1="0" Y2="200" Stroke="Black"/>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Margin="2">
<TextBlock.RenderTransform>
<TranslateTransform X="100" Y="100"/>
</TextBlock.RenderTransform>
hello world1
<LineBreak/>
hello world2
<LineBreak/>
hello world3
</TextBlock>
</Canvas>
</Grid>
I want the text to appear in the top-right quadrant of my Canvas instead of the bottom right quadrant.
Is it possible to do in WPF?
Currently the text is drawn from topleft to bottomright, I would like it do be drawn from bottomleft to topright.
I couldn't find an answer on the internet that works inside a Canvas.
In my production code the text should be able to be of any length and height.
Edit:
I've been asked to provide a fully working sample, so here goes:
XAML:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<!--The drawing area can be anything, a grid, a panel, a canvas... Can't just use specific alignment tools so I have to use a Transform-->
<Grid x:Name="DrawingArea" Background="Beige" MouseMove="UIElement_OnMouseMove">
<TextBlock x:Name="TextBlock" Margin="2">
hello world1
<LineBreak/>
hello world2
<LineBreak/>
hello world3
</TextBlock>
</Grid>
</Grid>
</Window>
Code behind:
using System.Windows.Input;
using System.Windows.Media;
namespace WpfApp1
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
private void UIElement_OnMouseMove(object sender, MouseEventArgs e)
{
var mousePos = e.GetPosition(DrawingArea);
TextBlock.RenderTransform = new TranslateTransform(mousePos.X, mousePos.Y);
}
}
}
Currently the text appears below the default Windows mouse cursor, I'd like it to appear above the default Windows mouse cursor.
You see it in the lower right part because of the TranslateTransform. You set it to X=100, Y=100. If you set Y=0 it should be on the top.
But you should consider some things with this code:
Why use TranslateTransform inside a canvas? You can just add the Canvas.Top and Canvas.Left properties to the TextBlock and that should do it. Use the TranslateTransform only if you're looking to animate the element, and even then, it's more convenient to set it to (0, 0), and change it only during the animation.
Why are you using the canvas at all? And more over why inside a Grid? You should be able to achieve what you want by using a single Grid, or even a DockPanel. A Canvas is used only for graphics, that should always remain in the same place. There are better solutions for data, especially if it's supposed to change during runtime.
If you want a cross in the background of your grid, you can try something like this:
<Grid
Width="200"
Height="200"
Background="Beige">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Line
X1="0"
X2="200"
Y1="100"
Y2="100"
Stroke="Black"
Grid.RowSpan="2"
Grid.ColumnSpan="2"/>
<Line
X1="100"
X2="100"
Y1="0"
Y2="200"
Stroke="Black"
Grid.RowSpan="2"
Grid.ColumnSpan="2"/>
<TextBlock
VerticalAlignment="Center"
HorizontalAlignment="Center" Margin="2"
Grid.Row="0"
Grid.Column="1">
hello world1
<LineBreak/>
hello world2
<LineBreak/>
hello world3
</TextBlock>
</Grid>
Add a grid to your canvas and set the properties
HorizontalAlignment="Right"
VerticalAlignment="Top"
<Canvas x:Name="newCanvas">
<Grid>
<Label Content="Hello World!"
HorizontalAlignment="Right"
VerticalAlignment="Top"
/>
</Grid>

Canvas ImageSource not showing image

Here is my xaml:
<StackPanel Height="333">
<Canvas x:Name="imageCanvas"
RenderOptions.BitmapScalingMode="NearestNeighbor"
RenderOptions.EdgeMode="Aliased">
<Canvas.Background>
<ImageBrush x:Name="image1"
Stretch="None"
AlignmentX="Left"
AlignmentY="Top">
</ImageBrush>
</Canvas.Background>
</Canvas>
<Canvas x:Name="overlayCanvas">
<Rectangle Name="dummyRectangle" Width="1" Height="2" Fill="Transparent" />
</Canvas>
</StackPanel>
Here is my C# code behind:
void PlayImages()
{
string testImageFolder = "C:\\TestImages";
DirectoryInfo d = new DirectoryInfo(testImageFolder);//Assuming Test is your Folder
FileInfo[] Files = d.GetFiles("*.tif"); //Getting Text files
image1.ImageSource = new BitmapImage(new Uri("C:\\TestImages\\ChanA_0001_0001_0001_0001.tif"));
}
However, when the C# code above executed, nothing happened on UI. I am wondering where should I change to make the image show up? Thanks.
It was the stack panel that causes the problem. I am not sure why, but if some of them are removed, then the image shows up. The xaml with some stack penal removed is like following:
<StackPanel HorizontalAlignment="Left">
<!--Controls:MenuControl/-->
<Controls:ToggleButtonControl Margin="0,0,0,0" Height="43" RenderTransformOrigin="0.5,-0.233" />
</StackPanel>
<Canvas x:Name="imageCanvas"
RenderOptions.BitmapScalingMode="NearestNeighbor"
RenderOptions.EdgeMode="Aliased" Margin="0,52,0,0">
<Canvas.Background>
<ImageBrush x:Name="image1"
Stretch="None"
AlignmentX="Left"
AlignmentY="Top"
ImageSource="{Binding Path=Bitmap, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
</ImageBrush>
</Canvas.Background>
</Canvas>
Your imageCanvas always has width and height zero, because you neither add any children, not set its Width or Height explicitly.
Change your XAML to use only one Canvas instead, and optionally (depending on the outer container and the children to be added) set its Width and Height properties:
<Canvas x:Name="overlayCanvas" Height="333" Width="500">
<Canvas.Background>
<ImageBrush x:Name="image1" ... />
</Canvas.Background>
<Rectangle ... />
</Canvas>

Centering a large rectangle inside a grid which dimensions are smaller (and ClipToBounds doesn't work)

I'm trying to position a rectangle in the center of a grid with a restricted height, like so:
<Grid ClipToBounds="False">
<Grid Background="LightBlue" Height="10" ClipToBounds="False" Margin="0,27,0,79">
<Rectangle Height="40" Width="20" Fill="Black" VerticalAlignment="Center" HorizontalAlignment="Center" ClipToBounds="False"/>
</Grid>
</Grid>
I've expected it to look like that:
But instead it looks like that:
I know the my child rectangle is bigger and it is understandable that it clips, however, my ClipToBounds have no effect of anything. After reading around, I found that indeed Grid does not respect "ClipToBounds".
I tried to use Canvas, as suggested in the aforementioned article by Dr.Wpf but I can't seem to get it right.
Is there anything I can do to make it look like the 1st picture, without resorting to C# code?
Thanks!
It's a little hard to tell exactly what your requirements are here. You said you tried it witha Canvas, but you can't seem to get it right. What didn't work?
I used this code:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="TestApp.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="175" Height="170" Background="LightGray">
<Grid>
<Canvas Background="LightBlue" Height="10"
Margin="0,27,0,79" VerticalAlignment="Top">
<Rectangle Height="40" Width="20" Fill="Black"
Canvas.Left="66" Canvas.Top="-15" />
</Canvas>
</Grid>
</Window>
and was able to essentially fake what your screenshot looked like. But (as you can tell by the Canvas.Left and Canvas.Top parts of my code) it is sort of hackish. You could get rid of the Canvas.Left by binding to the ActualWidth of the Canvas and using an IValueConverter that converts it to the correct value.
Edit:
After a little further exploration, I came up with a slightly less hackish way of doing it. Though the nesting kind of makes me cringe, the only thing hardcoded is the top margin to get it centered vertically. Again, that can be done with an IValueConverter, but you don't want that. I'm not sure I can get any better than this, unfortunately.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WpfApplication10.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Grid x:Name="LayoutRoot">
<Grid Background="LightBlue" Height="10" ClipToBounds="False" Margin="0,27,0,79">
<Canvas>
<Grid Width="{Binding ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType=Canvas}}"
Height="{Binding ActualHeight, RelativeSource={RelativeSource FindAncestor, AncestorType=Canvas}}">
<Canvas HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0 -40 0 0">
<Rectangle Height="40" Width="20" Fill="Black" ClipToBounds="False"/>
</Canvas>
</Grid>
</Canvas>
</Grid>
</Grid>
</Window>

Categories

Resources