Draw a Path programmatically - wpf

I'm learning drawing shapes in WPF. I want draw a Path programmatically, not through XAML. I don't know what can assign to Data property.
Path p = new Path();
p.Data = ???

Look at the sample in the MSDN:
//Add the Path Element
myPath = new Path();
myPath.Stroke = System.Windows.Media.Brushes.Black;
myPath.Fill = System.Windows.Media.Brushes.MediumSlateBlue;
myPath.StrokeThickness = 4;
myPath.HorizontalAlignment = HorizontalAlignment.Left;
myPath.VerticalAlignment = VerticalAlignment.Center;
EllipseGeometry myEllipseGeometry = new EllipseGeometry();
myEllipseGeometry.Center = new System.Windows.Point(50,50);
myEllipseGeometry.RadiusX = 25;
myEllipseGeometry.RadiusY = 25;
myPath.Data = myEllipseGeometry;
myGrid.Children.Add(myPath);
It is the line myPath.Data = myEllipseGeometry; that you are looking for. Just assign it a Geometry object.

Here's an example of something I was experimenting with:
using Windows.Foundation;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Shapes;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Data;
namespace GridNineExperiment
{
public class Hamburger : Button
{
static GeometryCollection DataHamburger = new GeometryCollection
{
new RectangleGeometry {Rect = new Rect{X = 0, Y = 0, Width = 20, Height = 5 }},
new RectangleGeometry {Rect = new Rect{X = 0, Y = 10, Width = 20, Height = 5 }},
new RectangleGeometry {Rect = new Rect{X = 0, Y = 20, Width = 20, Height = 5 }},
};
static Path PathHamburger = new Path
{
Fill = new SolidColorBrush(Colors.White),
Stroke = new SolidColorBrush(Colors.Black),
StrokeThickness = 1.0,
Data = new GeometryGroup { Children = DataHamburger }
};
public Hamburger()
{
Content = PathHamburger;
}
}

Related

Windows Phone 8.1 Silverlight Secondary Tile isostore error

I'm trying to render a UserControl as an image, and then assign it to a secondary tile and pin it. The resulting URI is
isostore:/Shared/ShellContent/CustomTile.jpg
However, I get the following error:
ExceptionObject = {System.ArgumentException: Value does not fall within the expected range.
at
Windows.UI.StartScreen.SecondaryTileVisualElements.put_Square150x150Logo(Uri value)
at NestWP.ActionTiles.d__1.MoveNext()
I have this piece of code
var customTile = new ActionTileControl();
customTile.Measure(new Size(150, 150));
customTile.Arrange(new Rect(0, 0, 150, 150));
var bmp = new WriteableBitmap(150, 150);
bmp.Render(customTile, null);
bmp.Invalidate();
const string filename = "/Shared/ShellContent/CustomTile.jpg";
using (var isf = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!isf.DirectoryExists("/CustomLiveTiles"))
{
isf.CreateDirectory("/CustomLiveTiles");
}
using (var stream = isf.OpenFile(filename, System.IO.FileMode.OpenOrCreate))
{
bmp.SaveJpeg(stream, 336, 366, 0, 100);
stream.Close();
}
bool ex = isf.FileExists(filename);
ex = ex;
}
string urilink = "isostore:" + filename;
SecondaryTile secondaryTile = new SecondaryTile()
{
TileId = "tileid",
DisplayName = "title",
Arguments = "args"
};
//Error on the line below
secondaryTile.VisualElements.Square150x150Logo = new Uri(urilink, UriKind.Absolute);
secondaryTile.VisualElements.ShowNameOnSquare150x150Logo = false;
bool isPinned = await secondaryTile.RequestCreateAsync();
I checked FileExists and the bool returns true.
How can I get the image to be set as secondary tile?
Hi maybe this source will help you
http://www.windowsapptutorials.com/windows-phone/how-to-create-secondary-tiles-on-windows-phone-start-screen-using-c/

Animation in codebehind for loop, using RenderTransform

Is it possible to animate the "old school" way, in codebehind, instead of xaml?
I just want an arrow that points to something with a 'bounce effect' which I could easily do in my own for loop. But I do not know how to refresh or do a timer delay, inside the loop. I already placed the image into position in codebehind. All I want to do is this simple animation...
public void validationArrow()
{
var validationArrow = new Image();
validationArrow.Source = new BitmapImage(new Uri("/SlProject;component/arrow.png", UriKind.RelativeOrAbsolute));
LayoutRoot.Children.Add(validationArrow);
validationArrow.Stretch = Stretch.None;
validationArrow.VerticalAlignment = System.Windows.VerticalAlignment.Top;
validationArrow.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
var arrowPosition = new TranslateTransform { X = 0, Y = 0 };
validationArrow.RenderTransform = arrowPosition;
validationArrow.Name = "validationArrow";
for (int i = 150; i >= 0; i--)
{
arrowPosition.X = i;
validationArrow.RenderTransform = arrowPosition;
// how can I refresh screen and do some timing here?
}
}
There's no school like the old school ;)
Here, this should help you on your way. You can play with the millisecond and Y translation values being passed to the BuildEasing method to change the 'bounce' effect's speed and distance.
private void RunStoryboard()
{
var arrowImage = new Image();
arrowImage.RenderTransform = new CompositeTransform();
arrowImage.Source = new BitmapImage(new Uri("/SlProject;component/arrow.png", UriKind.RelativeOrAbsolute));
LayoutRoot.Children.Add(arrowImage);
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(BuildKeyFrame(arrowImage));
storyboard.Begin();
}
private DoubleAnimationUsingKeyFrames BuildKeyFrame(Image target)
{
DoubleAnimationUsingKeyFrames kf = new DoubleAnimationUsingKeyFrames();
Storyboard.SetTarget(kf, target);
Storyboard.SetTargetProperty(kf, new PropertyPath("(UIElement.RenderTransform).(CompositeTransform.TranslateY)"));
kf.KeyFrames.Add(BuildEasing(100, 10));
kf.KeyFrames.Add(BuildEasing(200, 0));
kf.KeyFrames.Add(BuildEasing(300, 10));
kf.KeyFrames.Add(BuildEasing(400, 0));
kf.KeyFrames.Add(BuildEasing(500, 10));
kf.KeyFrames.Add(BuildEasing(600, 0));
return kf;
}
private EasingDoubleKeyFrame BuildEasing(int ms, int value)
{
return new EasingDoubleKeyFrame()
{
KeyTime = KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0, ms)),
Value = value
};
}

passing a vector drawing to the UI thread

Is there any way to draw actual WPF vectorgraphics (DrawingContext, VisualBrush, DrawingBrush, RenderTargetBitmap etc.) with Freezables in a separate thread offscreen?
The following solution almost has it, excpet that the drawing is a bitmap and is not scalable when this.label becomes big you'll the the pixels.
private void Draw()
{
this.dispatcher = Dispatcher.CurrentDispatcher;
Thread t = new Thread(this.DrawAsync);
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
private void DrawAsync(object state)
{
var b1 = new Button
{
Width = 50,
Height = 50,
Content = new TextBlock
{
FontSize = 16, FontFamily = new FontFamily("Arial"), FontWeight = FontWeights.Bold, Text = "Hello"
}
};
b1.Measure(new Size(50, 50));
b1.Arrange(new Rect(0, 0, 50, 50));
PixelFormat pixelFormat = PixelFormats.Default;
var elementBrush = new VisualBrush(b1);
var visual = new DrawingVisual();
using (var dc = visual.RenderOpen())
{
// preferably I'd like to draw controls too, but shapes and text would suffice too
dc.DrawRectangle(elementBrush, null, new Rect(0, 0, 50, 50));
dc.DrawEllipse(Brushes.Green, new Pen(Brushes.Black, 2), new Point(75, 25), 25, 15);
dc.Close();
}
var bitmap = new RenderTargetBitmap(100, 50, 96, 96, pixelFormat);
bitmap.Render(visual);
bitmap.Freeze();
var br = new ImageBrush(bitmap) { Stretch = Stretch.Uniform };
br.Freeze();
this.dispatcher.Invoke((ThreadStart)delegate { this.label.Background = br; });
}
You could use DrawingImage which is a type of freezeable. Load or fill it in a BackgroundWorker, freeze it and pass it to an Image in the Completed Event.

How can I use WPF bindings while printing?

It seems not all bindings are to evaluated when printing. For example, in the code below, only the first button has content = "100", other buttons have content = "0".
var doc = new XpsDocument("test.xps",FileAccess.Write);
var writer = XpsDocument.CreateXpsDocumentWriter(doc);
var collator = writer.CreateVisualsCollator();
collator.BeginBatchWrite();
for (int i = 0; i < 3; i++)
{
var button = new Button();
button.SetBinding(ContentControl.ContentProperty,
new Binding
{
RelativeSource = new RelativeSource(RelativeSourceMode.Self),
Path = new PropertyPath("ActualWidth")
});
button.Measure(new Size(100, 100));
button.Arrange(new Rect(0, 0, 100, 100));
button.Width = 100;
button.Height = 100;
collator.Write(button);
}
collator.EndBatchWrite();
doc.Close();
Is there a workaround?
For example, is there a way to force the binding to evaluate?
Have you tried making sure the dispatcher is idle before the call to collator.EndBatchWrite().
Something like:
Dispatcher.CurrentDispatcher.Invoke(
new Action( delegate { } ), DispatcherPriority.ApplicationIdle, null );

WPF image thumbnail with the offset

I have an image 800x600 and I would show a thumbnail 90x30 with some offset x=12 and y 12.
I have created a brush but I am struggling to apply an offset.
var source = new ImageBrush(groundSource);
source.Stretch = Stretch.None;
source.AlignmentX = AlignmentX.Left;
source.AlignmentY = AlignmentY.Top;
source.RelativeTransform = new TranslateTransform(0.5, 0);
var grid = new Grid();
grid.ClipToBounds = true;
grid.Background = source;
grid.VerticalAlignment = System.Windows.VerticalAlignment.Top;
grid.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
grid.Margin = new System.Windows.Thickness(12, 12, 0, 0);
grid.Width = SpriteSize.SpriteWidht + 33;
grid.Height = SpriteSize.SpriteHeight;
grid.SnapsToDevicePixels = true;
I would appreciate any suggestions.
There is a hacky solution for this problem:
Add Image as a child to the Grid.
Set Grid attribute as ClipToBounds=true
Set Image margin to control thumbnail offset.

Resources