How to clip image in Silverlight using custom Path (in code behind, not in XAML).
I have puzzle piece like shape written in path and want to use it to clip any image.
Currently it works by clipping using rectangle, The code is (C#):
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
int NUM_COLUMN = 8;
int NUM_ROW = 8;
double gridWidth = 60;
double gridHeight = 60;
string url = "Images/Sun.png";
// C#
for (int i = 0; i < NUM_COLUMN; i++)
{
for (int j = 0; j < NUM_ROW; j++)
{
double offsetX = (double)i * gridWidth;
double offsetY = (double)j * gridHeight;
Image image = new Image();
image.Source = new BitmapImage(new Uri(url, UriKind.Relative));
// clip the image
RectangleGeometry r = new RectangleGeometry();
r.Rect = new Rect(offsetX, offsetY, gridWidth, gridHeight);
image.Clip = r;
this.ClipCanvas.Children.Add(image);
}
}
}
There is only one Canvas in XAML called ClipCanvas.
Okay, not ideal. But works from the code-behind
Image image = XamlReader.Load(#"<Image xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" Clip=""M 41.1,33.7 C 41.1,33.7 39.9,32.2 39.9,30.8 C 39.9,30.6 39.5,29.8 39.3,29.5 C 39.1,29.3 38.4,28.6 37.8,28.2 C 37.2,27.9 35,26.6 34.6,22.4 Z "" />") as Image;
image.Source = new BitmapImage(new Uri("Desert.jpg", UriKind.Relative));
Set up in the clip in Xaml, and create the Image using an XamlReader. Tried other approaches, and this was the only one that worked.
Related
I am drawing a diagram of a switch network in WPF. I can add the switches and the connections between them to the diagram. the connections are drawn as Path with LineGeometry as the Data:
Shapes.Path path1;
path1 = new Shapes.Path();
path1.Stroke = Brushes.Black;
path1.StrokeThickness = 1;
LineGeometry line1 = new LineGeometry();
path1.Data = line1;
I add the line to the thumb that I am using to represent the switch:
SwitchAsThumb thumb1 = new SwitchAsThumb;
thumb1.StartLines.Add(line1);
Where SwitchAsThumb is defined as:
public class SwitchAsThumb : Thumb
{
public List<LineGeometry> EndLines { get; private set; }
public List<LineGeometry> StartLines { get; private set; }
}
and this method in my window xaml.cs file to update the end point position of the path:
public void UpdateSwitchConnections(SwitchAsThumb thumb)
{
double left = Canvas.GetLeft(thumb);
double top = Canvas.GetTop(thumb);
for (int i = 0; i < thumb.StartLines.Count; i++)
thumb.StartLines[i].StartPoint = new Point(left + thumb.ActualWidth / 2, top + thumb.ActualHeight / 2);
for (int i = 0; i < thumb.EndLines.Count; i++)
thumb.EndLines[i].EndPoint = new Point(left + thumb.ActualWidth / 2, top + thumb.ActualHeight / 2);
}
I was thinking I could place labels or similar at the same points on the canvas when the lines are updated, but I'm not sure the labels would move when the user drags the switches around to re-arrange the diagram. The method I've implemented to re-draw the thumbs when the user drags them around could probably be updated to move the labels but I'm hoping there's a cleaner solution.
I want to change 3D object point XYZ.
Is it possible ?
have you any reference? many reference tools have not Point3D Animation
how to use Point3D Property?
I want to make that :
http://www.youtube.com/watch?v=gTz7jSU-C5I
Animation
Storyboard s = new Storyboard();
ModelVisual3D MV = mainViewport.Children.ElementAt(current) as ModelVisual3D;
Model3DGroup cube = MV.Content as Model3DGroup;
for (int j = 0; j < cube.Children.Count; j++)
{
Model3DGroup Point_X= cube.Children[j] as Model3DGroup;
DoubleAnimation doubleAnimation = new DoubleAnimation();
doubleAnimation.To = 2;
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(2));
s.Children.Add(doubleAnimation);
s.Duration = new Duration(TimeSpan.FromSeconds(2));
Storyboard.SetTarget(doubleAnimation, cube);
Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath(" ??? "));
s.Begin(); // Exception during the execution.
}
I need to write a C# WPF program in order to let the user individually modify the width and height of a grid using the mouse. After some reading, I've found out that WPF featues the GridSplitter control, which seems to be a possible solution for my problem. So far, this is my approach:
private const int NumCols = 5;
private const int NumRows = 7;
private void CreateDynamicWPFGrid()
{
// Create the Grid
var dynamicGrid = new Grid();
for (int i = 0; i < NumCols - 1; ++i )
{
// Define 2 * (NumCols - 1) columns. For every two columns, the first one will hold a label
// whereas the second one will hold a vertical splitter.
var gridColDefA = new ColumnDefinition();
// The gridColDefB is for the splitter.
var gridColDefB = new ColumnDefinition();
gridColDefB.Width = new GridLength(1, GridUnitType.Auto);
dynamicGrid.ColumnDefinitions.Add(gridColDefA);
dynamicGrid.ColumnDefinitions.Add(gridColDefB);
}
{
// The last column only needs a cell for holding a label. No splitter whatsoever.
var gridColDef = new ColumnDefinition();
dynamicGrid.ColumnDefinitions.Add(gridColDef);
}
for (int j = 0; j < NumRows - 1; ++j)
{
var gridRowDefA = new RowDefinition();
var gridRowDefB = new RowDefinition();
// The gridRowDefB is for the splitter.
gridRowDefB.Height = new GridLength(1, GridUnitType.Auto);
dynamicGrid.RowDefinitions.Add(gridRowDefA);
dynamicGrid.RowDefinitions.Add(gridRowDefB);
}
{
// The last row only needs a cell for holding a label. No splitter whatsoever.
var gridRowDef = new RowDefinition();
dynamicGrid.RowDefinitions.Add(gridRowDef);
}
for (int i = 0; i < NumCols - 1; ++i )
{
for(int j = 0; j < NumRows - 1; ++j )
{
// Insert the label.
var label = new Label();
label.Content = "C" + i + "-R" + j;
label.Background = new SolidColorBrush(Colors.Azure);
Grid.SetColumn(label, 2 * i);
Grid.SetRow(label, 2 * j);
dynamicGrid.Children.Add(label);
// Insert the horizontal splitter.
var horizontalGridSplitter = new GridSplitter();
horizontalGridSplitter.Height = 1;
horizontalGridSplitter.Background = new SolidColorBrush(Colors.DarkSlateBlue);
horizontalGridSplitter.HorizontalAlignment = HorizontalAlignment.Stretch;
horizontalGridSplitter.VerticalAlignment = VerticalAlignment.Center;
Grid.SetColumn(horizontalGridSplitter, 2 * i );
Grid.SetRow(horizontalGridSplitter, 2 * j + 1);
Grid.SetRowSpan(horizontalGridSplitter, 1);
Grid.SetColumnSpan(horizontalGridSplitter, 1);
dynamicGrid.Children.Add(horizontalGridSplitter);
// Insert the vertical splitter.
var verticalGridSplitter = new GridSplitter();
verticalGridSplitter.Width = 1;
verticalGridSplitter.Background = new SolidColorBrush(Colors.DarkSlateBlue);
verticalGridSplitter.HorizontalAlignment = HorizontalAlignment.Center;
verticalGridSplitter.VerticalAlignment = VerticalAlignment.Stretch;
Grid.SetColumn(verticalGridSplitter, 2 * i + 1);
Grid.SetRow(verticalGridSplitter, 2 * j + 1);
Grid.SetRowSpan(verticalGridSplitter, 1);
Grid.SetColumnSpan(verticalGridSplitter, 1);
dynamicGrid.Children.Add(verticalGridSplitter);
}
}
// Display grid into a Window
Content = dynamicGrid;
}
The output I'm getting is as follows:
Notice that I'm only able to resize the rows (don't know why the vertical splitters don't show up) and, for some reason, when I grab a horizontal splitter it resizes the whole row and not just the individual cell. Any ideas? Please, See the following screenshot to see the resizing in action:
This is what I'd expect if I resize cell (0,0) (the image has being manually edited by me):
Thanks in advance!
If you remove the line setting the row for your verticalGridSplitter and set them to span NumRows, you will see your vertical splitters. But ultimately, I think you are trying to do something that the grid with splitters can't do. You can't resize the width and height of individual cells, only whole rows and columns.
After all, if you make C0-R0 taller, what do you expect the rest of that row to do?
Windows 7 (64 bit), .NET 4 (32 bit app)
I have a subclassed System.Windows.Forms.ListView comprising 2 columns displayed
in "Details" view. Only text fields are involved. The list comprises about 100
rows. On initial display all fields are drawn clearly but when scrolling or
"paging" with the scroll bar the text of some fields in the first column becomes
unreadable. It appears to be overwriten with random lines and blotches.
Is there anything that I can do to ensure that the text is clearly drawn in column 0?
The effect is diminished (clarity improved) when using remote desktop across a
LAN.
The effect disappears (all text is drawn clearly) when using remote desktop
across a WAN.
The ListView has always drawn perfectly on Windows XP.
For the purposes of a stripped down test, column header and DrawItem calls are ingored. The problem area is OnDrawSubItem which comprises the code
protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e)
{
using (StringFormat sf = new StringFormat(StringFormatFlags.NoWrap))
{
Rectangle rect = new Rectangle(e.Bounds.Left
,e.Bounds.Top, e.Bounds.Width, e.Bounds.Height);
e.Graphics.DrawString(e.SubItem.Text, this.Font, Brushes.Black
,rect, sf);
}
base.OnDrawSubItem(e);
}
The following is the complete code that reproduces the problem:
using System;
using System.Windows.Forms;
using System.Drawing;
///
/// Build by saving to a file called LVTrial.cs and then executing "csc LVTrial.cs"
/// Scroll list up and down on a windows 7 box and the first column of text is corrupted.
///
class MyListView : ListView
{
Random randomiser = new Random();
private const int NUM_ROWS = 100;
private const int NUM_COLS = 2;
public MyListView()
{
this.Location = new System.Drawing.Point(23, 25);
this.OwnerDraw = true;
this.Size = new System.Drawing.Size(625, 387);
this.TabIndex = 0;
this.UseCompatibleStateImageBehavior = false;
this.View = System.Windows.Forms.View.Details;
for (int ii = 0; ii < NUM_COLS; ii++)
{
this.Columns.Add((
(System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())));
}
for (int ii = 0; ii < NUM_ROWS; ii++)
{
this.Items.Add( new ListViewItem(
new string[NUM_COLS] { CreateRandomString(1, 6), CreateRandomString(1, 6) } ) );
}
}
protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e)
{
using (StringFormat sf = new StringFormat(StringFormatFlags.NoWrap))
{
Rectangle rect = new Rectangle(e.Bounds.Left
,e.Bounds.Top, e.Bounds.Width, e.Bounds.Height);
e.Graphics.DrawString(e.SubItem.Text, this.Font, Brushes.Black
,rect, sf);
}
base.OnDrawSubItem(e);
}
private string CreateRandomString(int minLength, int maxLength)
{
string str = string.Empty;
int length = randomiser.Next(minLength, maxLength + 1);
for (int ii = 0; ii < length; ii++)
{
int asciiChar = randomiser.Next(32, 126); // ascii range
str += Convert.ToChar(asciiChar);
}
return str;
}
}
class LVTrial : Form
{
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new LVTrial());
}
private LVTrial()
{
MyListView myListView = new MyListView();
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(674, 440);
this.Controls.Add(myListView);
this.Text = "LVTrial";
}
}
I have recorded this as a Windows 7 bug at https://connect.microsoft.com/VisualStudio/feedback/details/657909/subclassed-listview-column-0-displays-corrupted-text-on-windows-7
My own workaround for the problem was to insert an additional column at position 0. I now draw a rectangle with a transparent brush in column 0 for each item. All of which stops the text in the column to the right being drawn corrupt. I imagine drawing an image would achieve the same thing but I have not tried it. You can't hide this dummy column as the problem simply transfers to the second column (i.e. the first visible coolumn).
Another tip is that it seems to be performance related. The bug was more likely to occur with 100 items in the list view than 10,000.
my code below is supposed to display N lines per inch. instead i get a little more than N lines per inch. the distance between lines is somewhat smaller. in addition, changing the screen resolution makes the distance between lines change too. does anyone know how to handle that?
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace MyApp
{
class MyControl : Control
{
private readonly ContainerVisual container = new ContainerVisual();
private readonly DrawingVisual drawing = new DrawingVisual();
private void RenderDrawing()
{
var s = PresentationSource.FromVisual(this);
var dpiX = 96 * s.CompositionTarget.TransformToDevice.M11;
var dpiY = 96 * s.CompositionTarget.TransformToDevice.M22;
double N = 1;
using (var c = drawing.RenderOpen())
{
var p = new Pen(new SolidColorBrush(Colors.Black), 1);
for (int i = 0; i < 10; i++)
{
var x = i * dpiX / N;
c.DrawLine(p, new Point(x, 0), new Point(x, 100));
}
}
}
protected override Size ArrangeOverride(Size s)
{
RenderDrawing();
return s;
}
protected override Visual GetVisualChild(int index)
{
return container;
}
protected override Size MeasureOverride(Size s)
{
return new Size();
}
protected override int VisualChildrenCount
{
get { return 1; }
}
public MyControl()
{
container.Children.Add(drawing);
AddVisualChild(container);
}
}
}
this article seems to discuss the same problem: WPF DPI issues
there is no solution to this problem other than asking the user to set the correct DPI settings that correspond to the physical DPI of the screen. a workaround that i found that makes life a little easier is to use WPF application level scaling as described here: http://www.odewit.net/ArticleContent.aspx?id=WpfDpiScaling&lang=en&format=html
Not sure if this would accomplish what you are looking for, but it should help if the issue has to do with rounding. As I said in comments, your code looks mostly correct, I think it is a rounding issue with the dpi computation. Since you are desiring to render based on 96 dpi, compute the coordinates based on 96dpi and then convert the points to your device. I wrote this more for clarity, you could use a single array of points and just remember that i is the start point and i+1 is the end point and then you would only have to make a single call to transform the points.
private void RenderDrawing()
{
var s = PresentationSource.FromVisual(this);
var dpiX = 96;
int numberOfLines = 10;
double N = 1;
double spacing = dpiX / N;
var startPoints = new Point[numberOfLines]();
var endPoints = new Point[numberOfLines]();
for (int i = 0; i < numberOfLines; i++)
{
var x = i * spacing;
startPoints[i] = new Point(x, 0);
endPoints[i] = new Point(x, 100);
}
s.CompositionTarget.TransformToDevice.Transform(startPoints);
s.CompositionTarget.TransformToDevice.Transform(endPoints);
using (var c = drawing.RenderOpen())
{
using (var p = new Pen(new SolidColorBrush(Colors.Black), 1))
{
for(int i=0; i < numberOfLines; i++)
{
c.DrawLine(p, startPoints[i], endPoints[i]);
}
}
}
}