I've been trying to recreate this GUI purely in WPF, and I'm having problems:
The shadow. The shadow on the main element doesn't show inside the fill - when using DropShadowEffect in WPF, it does. As of yet I've found no solution to this.
Background images - the main element has a slight pattern in it, a diagonal one. But in WPF, I can't use background images like this. Chances are I'm just missing something.
The slight inset, in the main element (at the top) - not easily replicated.
So anyway, I guess my question is, how can I accomplish these kinds of effects in WPF?
Hopefully this snippet will point you in the right direction:
<Grid>
<Border x:Name="Blur"
BorderThickness="5"
CornerRadius="5"
BorderBrush="#7F000000">
<Border.Effect>
<BlurEffect Radius="8" />
</Border.Effect>
</Border>
<Border x:Name="Outter"
BorderBrush="#CCD3D3D3"
BorderThickness="1"
CornerRadius="5"
Margin="2">
<Border.Background>
<ImageBrush Viewbox="0,0,45,38"
ViewboxUnits="Absolute"
Viewport="0,0,45,38"
ViewportUnits="Absolute"
TileMode="Tile"
ImageSource="<SomeImageThatIsATileOfThePattern>"
Opacity="0.3"
Stretch="Fill" />
</Border.Background>
</Border>
<Border x:Name="Inner"
BorderThickness="0,1,0,0"
CornerRadius="5"
Margin="2,4,2,2"
BorderBrush="#7FD3D3D3" />
<ItemsControl Background="HotPink"
Margin="11"
Height="21" />
</Grid>
The result is:
[I used a generic image, just to show the repetition. The original image is W50xH38 in size - hope the repetition is noticeable]
Play with the values for Viewbox and Viewport to adjust to your image.
Of course, the ItemsControl should not have the pink background and its height should not be a constant, it was done for demo purposes.
Related
I tried using DropShadowEffect but it's "glow" strength weakens when you increase BlurRadius. I want to have strong outer glow like the image below.
If I stack the same effect a dozen times I am able to get this, but the performance tanks after this. Is this possible to do using WPF with a single effect?
Depending on how large you want the radius of the blur to be and how smooth the result needs to be, you could stack different effects like gradient stops instead of repeatedly stacking the same effect.
Like you pointed out, the DropShadowEffect strength gets weaker as the BlurRadius increases.
<TextBox Text="DropShadowEffect">
<TextBox.Effect>
<DropShadowEffect BlurRadius="50"
ShadowDepth="0"
Color="Blue"
Opacity="1"/>
</TextBox.Effect>
</TextBox>
Additionally, applying effects directly to the TextBox impacts the rendering quality of the text. The proposed solution to the linked question (setting TextOptions.TextFormattingMode="Display" on the Window) also has layout implications. Instead, you can draw a Rectangle with a BlurEffect behind your element.
<Rectangle Fill="Blue"
Height={Binding ElementName=MyTextBox, Path=ActualHeight}"
Width={Binding ElementName=MyTextBox, Path=ActualWidth}">
<Rectangle.Effect>
<BlurEffect Radius="50"/>
</Rectangle.Effect>
</Rectangle>
<TextBox x:Name="MyTextBox" Text="Rectangle with BlurEffect"/>
You can then add an additional Rectangle for each gradient stop. Here there are two: one at 50 to define the overall size of the blur, and one at 30 to strengthen the glow around the control.
<Rectangle Fill="Blue"
Height={Binding ElementName=MyTextBox, Path=ActualHeight}"
Width={Binding ElementName=MyTextBox, Path=ActualWidth}">
<Rectangle.Effect>
<BlurEffect Radius="50"/>
</Rectangle.Effect>
</Rectangle>
<Rectangle Fill="Blue"
Height={Binding ElementName=MyTextBox, Path=ActualHeight}"
Width={Binding ElementName=MyTextBox, Path=ActualWidth}">
<Rectangle.Effect>
<BlurEffect Radius="30"/>
</Rectangle.Effect>
</Rectangle>
<TextBox x:Name="MyTextBox" Text="Two Rectangles with BlurEffect"/>
You asked about the perceived sharpness around the corners of the TextBox and I must admit I don't have a good solution. I initially considered rounding the corners of the blurred elements behind your control by using a Border instead of a Rectangle, but I honestly don't see much of a difference.
<!-- Remove the CornerRadius property for square corners. -->
<Border CornerRadius="10" Background="Blue">
<Border.Effect>
<BlurEffect Radius="50"/>
</Border.Effect>
</Border>
<Border CornerRadius="10" Background="Blue">
<Border.Effect>
<BlurEffect Radius="30"/>
</Border.Effect>
</Border>
Of course, you could always make the background objects larger than your control. Here they are in the same cell of a Grid but there is extra space for the Border to grow because the TextBox has a Margin. A smaller top/bottom margin and larger left/right margin means the glow will be more uniform around the control.
<!-- These items should be in the same cell of a Grid -->
<Border CornerRadius="10" Background="Blue">
<Border.Effect>
<BlurEffect Radius="50"/>
</Border.Effect>
</Border>
<Border CornerRadius="10" Background="Blue">
<Border.Effect>
<BlurEffect Radius="30"/>
</Border.Effect>
</Border>
<TextBox Text="TextBox has an 8px, 4px margin" Margin="8 4"/>
I want a picture with transparent background to be a button.
The shape of the picture is custom (not an ellipse or something like that). So, I need it to be lighted and be possible to press (in the shape of 1 itself!).
I've only started working on WPf and don't know how to do this. And I couldn't really figure out how to do it in my case (although there are alike questions on the platform).
Would be very thankful if you give me a detailed answer!
<Button>
<Image Source="num1"/>
<Button.Template>
<ControlTemplate TargetType="Button">
<ContentPresenter Content="{TemplateBinding Content}"/>
</ControlTemplate>
</Button.Template>
</Button>
You can set the template of the button something like this:
<Image Source="num1.png"
Width="16"
Height="16"/>
Also this might help
<Button.Background>
<ImageBrush ImageSource="num1.png" Stretch="Fill" TileMode="None" />
</Button.Background>
It sounds like you need to handle a limited number of pictures and if all of them are relatively simple like that "1" the task seems doable. The most challenging part is to construct the geometry element that cuts the button in its specific shape. If you only have the images in raster formats (*.png, *.jpg, *.bmp - a rectangular map of colored pixels), you will first have to them to vector images (presented with a set of mathematical functions instead of pixel data). It is not a trivial task, but if an image has a simple outline, you should be able to get good results. There are different pieces of software that handle this problem. Here is some blog post on this topic, but if does not meet your needs, you can also search for "How to trace a raster image", "Convert a raster image to a vector one" etc. If you are successful at this step, you will get some SVG images. Alas WPF does not support SVG images, as it has its own "language" for translating geometry data. So the svgs should be translated to WPF Geometries. I found some blogs while looking for "SVG to XAML", "SVG to WPF path" etc. Here is one with several approaches to the task.
When you have the WPF Geometries, you will be able to cut the button like this:
<Button>
<Button.Template>
<ControlTemplate>
<Image Source=". . .">
<Image.Clip>
<Geometry . . . />
</Image.Clip>
</Image>
</ControlTemplate>
</Button.Template>
</Button>
Of course, you can make it much more maintainable if you can create a custom control type that has the image data and geometry data exposed as properties, and then bind them in the template.
On the bottom line, this is not an easy task, which can become even more cumbersome if you have to add new geometries in the future. As Clemens mentioned in the comments, sticking with rectangular images that are hit testable in the whole bounding rectangle will make the task immensely easier.
You can draw a graph by yourself,and you can get Path Data via the link below
Get path geometry from image
<Button Width="100" Height="100" >
<Button.Template >
<ControlTemplate>
<Path x:Name="path" Data="xxxxx " Stretch="Fill" Fill="Azure" RenderTransformOrigin="0.5,0.5">
<Path.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Path.RenderTransform>
<Path.Effect>
<DropShadowEffect ShadowDepth="0" BlurRadius="22" Color="#FF646464"/>
</Path.Effect>
</Path>
</ControlTemplate>
</Button.Template>
</Button>
I'm developping a universal app for Windows in XAML/C# and I can't manage to create a circle button that I can resize. I use an Ellipse with uniform stretch so as to make it circle and a ContentPresenter.
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Stretch="Uniform">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
The problem is a uniform ellipse is automatically aligned top, left, and it's impossible to make it stretch the grid. When I resize the button, the ContentPresenter stays in the center while the ellipse stays in the top left corner. I'd like to be able to resize the button and that the text stays in the center of the circle.
Thanks for help!
You may use a Path with a circular EllipseGeometry:
<ControlTemplate TargetType="Button">
<Grid>
<Path Stretch="Uniform" ...>
<Path.Data>
<EllipseGeometry RadiusX="1" RadiusY="1"/>
</Path.Data>
</Path>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
You would however have to explicitly set the Width or Height of the Button, otherwise it would take up all available space.
I've also found another solution which is to use a ViewBox:
<ControlTemplate TargetType="Button">
<ViewBox>
<Grid>
<Ellipse Stretch="Uniform" Width="50" Height="50">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ViewBox>
</ControlTemplate>
The ViewBox automatically scales everything when resized. You have to set Width and Height, but it's only to set proportions. Very useful when using the user control with both Windows and Windows Phone.
Thanks for your answers!
I have an InkPresenter and this image with a transparent background. I want my strokes to be drawn only in the transparent area and ignore the black border of the shape. How is it possible?
here is an example using WPF, same applies to InkPresenter, you can use InkPresenter.Clip property to define the clip region
<Border BorderBrush="Green"
BorderThickness="1"
Width="200"
Height="200">
<Grid>
<InkCanvas>
<InkCanvas.Clip>
<EllipseGeometry RadiusX="98"
RadiusY="98"
Center="100,100" />
</InkCanvas.Clip>
</InkCanvas>
<Ellipse Stroke="Blue"
StrokeThickness="2" />
</Grid>
</Border>
result
I was able to solve my problem using Opacity Mask:
<InkPresenter.OpacityMask>
<ImageBrush ImageSource="{Binding ImageMask}" />
</InkPresenter.OpacityMask>
I'm working on a project with the kinect (I'm adding in case someone has a good way to do using the kinect) but I think this is mostly some programming issue in C# and WPF. I want to make to have 2 pictures, one on top of the other and with a mouse click, be able to scratch the first picture out. I tried using inkcanvas and put the picture in the inkcanvas but I can only draw on top of it.
Can someone give me an idea or some methods he think it would be better way to proceed?
An idea might be using an OpacityMask which is a VisualBrush that contains your InkCanvas.
This is what I did, Thanks #HB for your help. part of the code comes from
http://geekswithblogs.net/tkokke/archive/2009/03/02/scratchcard-in-wpf.aspx if anyone wants to know or need it.
<Border Background="#FF909090" BorderBrush="#FF000000"
BorderThickness="2,2,2,2">
<Grid Width="Auto" Height="Auto">
<Grid.Background>
<ImageBrush ImageSource="birthday_cake_by_protoperahe.jpg"/>
</Grid.Background>
<InkCanvas x:Name="inkCanvas"
Background="{x:Null}">
<InkCanvas.DefaultDrawingAttributes>
<DrawingAttributes Height="25" Width="25"/>
</InkCanvas.DefaultDrawingAttributes>
</InkCanvas>
<Image IsHitTestVisible="False" Source="planet.jpg" Stretch="Fill">
<Image.OpacityMask>
<VisualBrush
Visual="{Binding ElementName=inkCanvas}"/>
</Image.OpacityMask>
</Image>
</Grid>