I need to write a control, which will look like this:
Click Here to se callout
Problem is that i cant get label's real size to redraw my rectangle geometry. Label's height is always much bigger then space that it really occupies on the screen. I dont know, what to. Here is code:
<Popup x:Class="Controls.Callout"
x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" >
<Grid>
<Image>
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing >
<GeometryDrawing Brush="Orange" x:Name="geometryDrawing">
<GeometryDrawing.Pen>
<Pen Brush="Black" Thickness="2"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<CombinedGeometry GeometryCombineMode="Union">
<CombinedGeometry.Geometry1>
<RectangleGeometry x:Name="rectangel"
RadiusX="15" RadiusY="15"
Rect="0,30, 300,100"
/>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<PathGeometry>
<PathFigure StartPoint="30,30" IsClosed="False">
<PolyLineSegment Points="15,0, 90,30"/>
</PathFigure>
</PathGeometry>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
<Label Padding="5 20" MaxWidth="300" Name="myLabel" FontSize="16" >
<!--Content="{Binding}">-->
<!--MaxHeight="100" MaxWidth="300">-->
<AccessText TextWrapping="Wrap" MaxHeight="50"/>
</Label>
</Grid>
</Popup>
Code behind:
internal partial class Callout : Popup
{
public Callout()
{
InitializeComponent();
}
protected override void OnOpened(System.EventArgs e)
{
rectangel = new RectangleGeometry(new Rect(0,30,300, myLabel.Height/2));
}
}
Why not use a Grid with a Rectangle with rounded corners, a TextBlock, and some shape on top of the rectangle to make the callout "pointer"? As a Grid, the rectangle can automatically expand to the full size needed by the TextBlock.
For example, you can create a UserControl (or a full-fledged templated control) and given it a MaxWidth so that the text wraps. Then put the control in a Canvas so that it can determine its own size.
<UserControl MaxWidth="200">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Rectangle Grid.Row="1" RadiusX="50" RadiusY="50"
StrokeThickness="8" Stroke="Gray" />
<!-- Here will be pointer in Grid.Row="0"-->
<TextBlock Grid.Row="1" Name="myLabel" Margin="20" Foreground="Black"
Text="This is the textblock....." FontSize="20" TextWrapping="Wrap" />
</Grid>
</UserControl>
Related
This question already has answers here:
Content of a Button Style appears only in one Button instance
(3 answers)
Closed 4 years ago.
Icons in my application are stored as geometry drawings in a resource dicitony. for example:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Viewbox x:Key="ViewboxIconClose"
Width="16"
Height="16">
<Rectangle Width="16" Height="16">
<Rectangle.Fill>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#00FFFFFF" Geometry="F1M16,16L0,16 0,0 16,0z" />
<GeometryDrawing Brush="#FFFFFFFF" Geometry="F1M9.4141,8L13.9571,12.543 12.5431,13.957 8.0001,9.414 3.4571,13.957 2.0431,12.543 6.5861,8 2.0431,3.457 3.4571,2.043 8.0001,6.586 12.5431,2.043 13.9571,3.457z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
</Viewbox>
This icon is used like this:
<Button>
<StaticResource ResourceKey="ViewboxIconClose" />
</Button>
Now my Problem:
if i use this geometry somewhere else, it will only work at one place. for example if i use this geometry in a menu, the geometry on the button will disapear in the moment, i open the menu.
You could use x:Shared=false to solve this but I'd probably use a style and an image instead. The image should be more efficient than a rectangle with a brush and a viewbox.
Title="MainWindow" Height="350" Width="525"
xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
>
<Window.Resources>
<Style x:Key="CloseIcon" TargetType="Image">
<Setter Property="Stretch" Value="Uniform"/>
<Setter Property="Source">
<Setter.Value>
<DrawingImage PresentationOptions:Freeze="True">
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="#00FFFFFF" Geometry="F1M16,16L0,16 0,0 16,0z" />
<GeometryDrawing Brush="#FFFFFFFF" Geometry="F1M9.4141,8L13.9571,12.543 12.5431,13.957 8.0001,9.414 3.4571,13.957 2.0431,12.543 6.5861,8 2.0431,3.457 3.4571,2.043 8.0001,6.586 12.5431,2.043 13.9571,3.457z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<StackPanel>
<Grid Height="100" Width="100" Background="Red">
<Image Style="{StaticResource CloseIcon}"/>
</Grid>
<Grid Height="30" Width="30" Background="Blue">
<Image Style="{StaticResource CloseIcon}"/>
</Grid>
</StackPanel>
</Grid>
With this specific requirement you could just use one geometry as data for a path. Geometries aren't visuals.
The XAML that I have in my question was taken directly from this question on SO. It's simply XAML that creates a tiled DrawingBrush to render rectangles (squares in my case) against the background of a canvas. My problem is that this XAML only works when I set the Width and Height of the Canvas to anything other than "Auto". But when I set the Width and Height of canvasMain to Auto then no squares are drawn on the background.
How can I have my Width and Height set to "Auto" and also have the DrawingBrush render the squares on my canvas?
Here is my XAML:
<Window.Resources>
<DrawingBrush x:Key="GridTile" Stretch="None" TileMode="Tile"
Viewport="0,0 20,20" ViewportUnits="Absolute">
<!-- ^^^^^^^^^^^ set the size of the tile-->
<DrawingBrush.Drawing>
<GeometryDrawing>
<GeometryDrawing.Geometry>
<!-- draw a single X -->
<GeometryGroup>
<!-- top-left to top-right -->
<LineGeometry StartPoint="0,0" EndPoint="20,0" />
<!-- top-left to bottom-left -->
<LineGeometry StartPoint="0,0" EndPoint="0,20" />
<!-- bottom-left to bottom-right -->
<LineGeometry StartPoint="0,20" EndPoint="20,20" />
<!-- top-right to bottom-right -->
<LineGeometry StartPoint="20,0" EndPoint="20,20" />
</GeometryGroup>
</GeometryDrawing.Geometry>
<GeometryDrawing.Pen>
<!-- set color and thickness of lines -->
<Pen Thickness="1" Brush="Silver" />
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
<DrawingBrush x:Key="OffsetGrid" Stretch="None" AlignmentX="Left" AlignmentY="Top">
<DrawingBrush.Transform>
<!-- set the left and top offsets -->
<TranslateTransform X="0" Y="0" />
</DrawingBrush.Transform>
<DrawingBrush.Drawing>
<GeometryDrawing Brush="{StaticResource GridTile}" >
<GeometryDrawing.Geometry>
<!-- set the width and height filled with the tile from the origin -->
<RectangleGeometry Rect="0,0 160,160" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Window.Resources>
<Canvas Name="canvasMain" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" Width="Auto" Height="Auto" Background="{StaticResource OffsetGrid}"></Canvas>
Try changing the alignments:
<Canvas Name="canvasMain" HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Stretch" Width="Auto" Height="Auto" Background="{StaticResource OffsetGrid}"></Canvas>
I can't figure how to bind the height of a polygon to the height of my stack panel.
If I wanted to add a rectangle, all I had to do is something like that:
<Rectangle Width="75" >
<Rectangle.Fill>
<SolidColorBrush Color="Red" />
</Rectangle.Fill>
</Rectangle>
This one won't brake the height of the panel. but with the polygon it seems like I can't leave some of the points as blank so that will scale with the parent panel.
Thanks
Wrap your polygon with a <Viewbox>.
The Viewbox automatically scales its content to its size. Exactly how it does so can be tweaked with the Stretch and StretchDirection properties.
this solution works too
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<Border BorderBrush="Black" BorderThickness="1,1,0,1">
<StackPanel Orientation="Horizontal">
<TextBlock Text="TextBlock1" Margin="2" />
<TextBlock Text="TextBlock2" Margin="2" />
<TextBlock Text="TextBlock3" Margin="2" />
<TextBlock Text="TextBlock4" Margin="2" />
<TextBlock Text="TextBlock5" Margin="2" />
</StackPanel>
</Border>
<Path Fill="Yellow" Stroke="Black" StrokeThickness="1"
Width="50" Stretch="Fill">
<Path.Data>
<PathGeometry>
<PathFigure IsClosed="True" StartPoint="1,0.5">
<LineSegment Point="0,0" IsSmoothJoin="True" />
<LineSegment Point="0,1" IsSmoothJoin="True" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</StackPanel>
</Grid>
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Black">
<!-- Rounded yellow border -->
<Border BorderThickness="3" BorderBrush="Yellow" CornerRadius="10" Padding="2"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid>
<!-- Rounded mask (stretches to fill Grid) -->
<Border Name="mask" Background="White" CornerRadius="7"/>
<!-- Main content container -->
<StackPanel>
<!-- Use a VisualBrush of 'mask' as the opacity mask -->
<StackPanel.OpacityMask>
<VisualBrush Visual="{Binding ElementName=mask}"/>
</StackPanel.OpacityMask>
<!-- Any content -->
<Image Source="http://chriscavanagh.files.wordpress.com/2006/12/chriss-blog-banner.jpg"/>
<Rectangle Height="50" Fill="Red"/>
<Rectangle Height="50" Fill="White"/>
<Rectangle Height="50" Fill="Blue"/>
</StackPanel>
</Grid>
</Border>
</Page>
This XAML is from WPF – Easy rounded corners for anything but it doesn't work form me =(
<Border Canvas.Left="55"
Canvas.Top="30"
Width="100"
Height="Auto"
Margin="12,12,8,0"
VerticalAlignment="Top"
BorderBrush="#FF3B5998"
BorderThickness=".5"
CornerRadius="18">
<Border.Effect>
<DropShadowEffect BlurRadius="5"
Opacity=".5"
ShadowDepth="3" />
</Border.Effect>
<Border Name="ReceiverColor"
BorderBrush="#FF96B2E4"
BorderThickness="6"
CornerRadius="15">
<Border Name="Mask"
BorderBrush="#FF3B5998"
BorderThickness=".5"
CornerRadius="13">
<StackPanel>
<StackPanel.OpacityMask>
<VisualBrush Visual="{Binding ElementName=Mask}" />
</StackPanel.OpacityMask>
<Image Name="Receiver" />
</StackPanel>
</Border>
</Border>
</Border>
--- EDIT ---
I make borders sizes to auto and change source of image to an image from a link
when window loaded border size becomes as image size but image not shown !!!
You can define a <Border/> element and set its <Border.Background/>
property to an <ImageBrush/> , set the Borders CornerRadius property and you
are all set!
<Border CornerRadius="8,0,8,0">
<Border.Background>
<ImageBrush Stretch="Fill" ImageSource="ImageSource"/>
</Border.Background>
</Border>
You forgot the Grid that makes the mask and the image siblings and nested the image in the mask. and you forgot to set the background of the mask.
This works:
<Grid>
<Border Canvas.Left="55"
Canvas.Top="30"
Width="100"
Height="Auto"
Margin="12,12,8,0"
VerticalAlignment="Top"
BorderBrush="#FF3B5998"
BorderThickness=".5"
CornerRadius="18">
<Border.Effect>
<DropShadowEffect BlurRadius="5"
Opacity=".5"
ShadowDepth="3" />
</Border.Effect>
<Border Name="ReceiverColor"
BorderBrush="#FF96B2E4"
BorderThickness="6"
CornerRadius="15">
<Grid>
<Border Name="Mask"
Background="White"
BorderBrush="#FF3B5998"
BorderThickness=".5"
CornerRadius="13">
</Border>
<StackPanel>
<Image Name="Receiver"
Source="/Images/test.jpg" />
<StackPanel.OpacityMask>
<VisualBrush Visual="{Binding ElementName=Mask}" />
</StackPanel.OpacityMask>
</StackPanel>
</Grid>
</Border>
</Border>
</Grid>
in wpf this one works for me
<Ellipse Width="50" Height="50">
<Ellipse.Fill>
<ImageBrush ImageSource="http://chriscavanagh.files.wordpress.com/2006/12/chriss-blog-banner.jpg" />
</Ellipse.Fill>
</Ellipse>
None of the above answers worked for me completely. I was trying to implement rounded corners on image which could be resized and has properties Stretch="UniformToFill" VerticalAlignment="Center" and HorizontalAlignment="Center".
The center alignments keeps the middle part cropped as opposed to bottom and right side being cropped, when image is resized. Solutions with image brush were working but I was facing problem in keeping the content at center cropped.
The marked answer has a problem with transparent non rectangular images as the "mask" border will end up showing as white background. Following was the imlementation which worked for me:
<Grid>
<WrapPanel Name ="container">
<Image Source="sample_image.png" VerticalAlignment="Center" HorizontalAlignment="Center" Stretch="UniformToFill"/>
<WrapPanel.OpacityMask>
<VisualBrush >
<VisualBrush.Visual>
<Border Height="{Binding ElementName=container, Path=ActualHeight}"
Width="{Binding ElementName=container, Path=ActualWidth}"
Background="White" CornerRadius="15" />
</VisualBrush.Visual>
</VisualBrush>
</WrapPanel.OpacityMask>
</WrapPanel>
</Grid>
You can use an ellipse like how Usman Ali has said (I thought this myself and I didn't take it from him)
It's very simple, make an ellipse with the properties you want, then set the fill to an imagebrush with your desired image like this in XAML:
<Ellipse Height="Auto" Width="100">
<Ellipse.Fill>
<ImageBrush ImageSource="YOUR IMAGE SOURCE/LINK HERE"/>
</Ellipse.Fill>
</Ellipse>
In C#, if in any case you want to do in C#:
Ellipse YourEllipseName = new Ellipse
{
Height = 50,
Width = 50,
StrokeThickness = 0,
Fill = new ImageBrush
{
Stretch = Stretch.Uniform,
ImageSource = new BitmapImage(new Uri("YOUR IMAGE SOURCE HERE"))
}
};
<Grid Background="Black">
<Rectangle RadiusX="20" RadiusY="20"
Width="130"
Height="130">
<Rectangle.Fill>
<ImageBrush x:Name="myImage" ImageSource="C:\Path\Desktop\visual-studio-2010-logo.png"/>
</Rectangle.Fill>
</Rectangle>
</Grid>
We have some xaml:
<Style TargetType="local:V_RelLine">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:V_RelLine">
<Grid x:Name="LayoutRoot">
<VisualStateManager.VisualStateGroups>
</VisualStateManager.VisualStateGroups>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Ellipse x:Name="startArrow" Height="20" Width="60" Fill="Green" Stroke="Blue" Visibility="Visible" />
<Path x:Name="LinePathPart" Visibility="Visible" Stroke="Red" StrokeDashArray="2 2" StrokeThickness="2"
>
<Path.Data>
<PathGeometry x:Name="LinePathGeometry" >
<PathFigure x:Name="linePathBezierFigure" >
<BezierSegment x:Name="linePathBezierSegment" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<Ellipse x:Name="endArrow" Height="20" Width="20" Fill="Red" Stroke="Red" Visibility="Visible" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And in the code behind:
LinePathBezierFigure.StartPoint = startPoint;
Canvas.SetLeft(startArrow, startPoint.X);
Canvas.SetTop(startArrow, startPoint.Y);
/* similar for endArrow */
At runtime, startArrow and endArrow end up at the same point (even though they were set to different locations), as though they ended up at 0,0.
In fact, a subsequent call to Canvas.GetLeft(startArrow) show that it is at 0,0.
What is going on? Why are different objects in the same template, assigned the same coordinates, ending up in different locations?
Thanks for any insight in to this....
Just a thought but Canvas.Left and Canvas.Top normally only work well when the elements are placed in a Canvas rather than a Grid like you are using currently.