How to resize images in Silverlight 4? - silverlight

Doing something like this doesn't work.
foreach (Image img in Canvas1.Children.OfType<Image>())
{
double h = img.Height / 2;
double w = img.Width / 2;
img.Height = h;
img.Width = w;
img.UpdateLayout();
Canvas1.UpdateLayout();
}
Must I transform the BitmapImage which I assign to the Image with some kind
of Transform-class or something like that?

I just tested changing the size of images and it worked for me:
foreach (var item in _grid.Children.OfType<Image>())
{
item.Width = 400; // Update calls are unnecessary
}
One thing that might be wrong with your code is that you access Image.Height/Width without setting it first. If those properties are not set they are on Auto (which is Double.NaN), if you want to retrieve the current values which are calculated by the layout system use ActualHeight/Width.

Related

WPF-Rendering with TranslateTransform and Label

i do have the following Code:
private static void AddElements(Canvas canvas)
{
double canvasHeight = canvas.Height;
double canvasWidth = canvas.Width;
double y0 = canvasHeight / 2;
double x0 = canvasWidth / 2;
// Defining the new Coordinate-Point (0,0) to mid auf Canvas
TranslateTransform tt = new TranslateTransform(x0, y0);
Line line1 = new Line();
line1.X1 = -350;
line1.Y1 = 0;
line1.X2 = 350;
line1.Y2 = 0;
line1.Stroke = Brushes.Black;
line1.StrokeThickness = 2.0;
line1.RenderTransform = tt;
canvas.Children.Add(line1);
Line line2 = new Line();
line2.X1 = 0;
line2.Y1 = -350;
line2.X2 = 0;
line2.Y2 = 350;
line2.Stroke = Brushes.Black;
line2.StrokeThickness = 2.0;
line2.RenderTransform = tt;
canvas.Children.Add(line2);
Label lblN = new Label();
lblN.Width = 50;
lblN.Background = Brushes.Red;
lblN.Margin = new System.Windows.Thickness(0, -350, 0, 0);
lblN.Content = $"N";
lblN.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Center;
lblN.VerticalContentAlignment = System.Windows.VerticalAlignment.Center;
lblN.RenderTransform = tt;
lblN.Padding = new System.Windows.Thickness(0);
lblN.BorderBrush = Brushes.Black;
lblN.BorderThickness = new System.Windows.Thickness(2.0);
lblN.RenderTransform = tt;
canvas.Children.Add(lblN);
Label lblS = new Label();
lblS.Width = 50;
lblS.Background = Brushes.Red;
lblS.Margin = new System.Windows.Thickness(0, 350, 0, 0);
lblS.Content = $"S";
lblS.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Center;
lblS.VerticalContentAlignment = System.Windows.VerticalAlignment.Center;
lblS.RenderTransform = tt;
lblS.Padding = new System.Windows.Thickness(0);
lblS.BorderBrush = Brushes.Black;
lblS.BorderThickness = new System.Windows.Thickness(2.0);
lblS.RenderTransform = tt;
canvas.Children.Add(lblS);
}
this method is called on an Menu-Eventhandler and it shows an coordinate system with (0,0) in the mid of the canvas. It should show a label with "N" at the top and a label with "S" at the bottom.
But i shows the attached image
Does anyone know, why lblN looks different than lblS ?
best regards
Volkhard
=============
if i set the height of both Label-Objects to 15
lblN.Height=15
:
lblS.Height=15
i get the following:
i expected the lblN to be more upper on the y-coordinate.
What's causing it
Through a bit of testing, I can definitely say that it's the lblN.Margin = new System.Windows.Thickness(0, -350, 0, 0); that's causing the problem. Apparently, when you give a Label a negative margin like that, it will move upwards only as far is it's Height, and then it will start expanding instead of just continuing to move. So you end up with a Label that's 350 tall. We could try to figure out why that is, but really, that would be missing the point.
Admittedly, I don't have any direct documentation to back up the following statement this, but from years of experience in WPF I feel I can say:
Margin is intended to be used to give space between elements in a dynamic layout, not to give an element an absolute position.
This behavior of the Label seems to strengthen the idea that using Margin in this way was not something that was planed for by the designers.
What you should do instead
Canvas has tools for giving an element a set position, yet nowhere do you use Canvas's SetLeft, SetTop, SetRight, or SetBottom. Take a look at the example on MSDN. You shouldn't need to use a TranslateTransform or set Margin at all. Instead, you should calculate where you want the element to be and use one of the above four listed methods to assign that position.
Extra Tip
Don't use canvas.Height and canvas.Width, use canvas.ActualHeight and canvas.ActualWidth instead. The first pair only work if you are explicitly setting the size of the Canvas (which it seems you are). But in a senario where the Canvas is dynamically sized, the first pair will be NaN. The second pair always return the actual size that the Canvas is.
This doesn't make a difference in your current use case, but it might later on. If you're doing calculations based on the actual size of an element (as opposed to the size you might want it to be), always use ActualHeight and ActualWidth.

How to show multiple icons on winforms tabcontrol tab page?

I don't know if it is even possible, but maybe someone found a way to do this...
I have a tab control to which I allow the user to add tabs with a button click.
I want to show some icons on the tab so I added an ImageList, but I can show only one icon at a time, and I need to show at least 3 icons together.
I thought about having an image of 3 icons together, but the icons are shown after some actions the use do. For example: at first I show icon_1 and if the user clicks some where I add icon_2 etc...
Can someone come up with a way to do this ?
Thank you very much in advance...
No. It's not possible. Using the standard WinForms TabControl component you only can show one image at the same time.
The solution here, is using overlay icons. You have a base icon, and you add decorators. This is how Tortoise SVN, for example,
The following code builds an overlayed image in C#:
private static object mOverlayLock = new object();
public static Image GetOverlayedImage(Image baseImage, Image overlay)
{
Image im = null;
lock (mOverlayLock)
{
try
{
im = baseImage.Clone() as Image;
Graphics g = Graphics.FromImage(im);
g.DrawImage(overlay, 0, 0, im.Width, im.Height);
g.Dispose();
}
catch
{
// log your exception here
}
}
return im;
}
NOTE: The overlayed image must have the same size than the base image. It must have transparent color, and the decorator in the overlayed image must be placed in the right place, for example bottom-right or top-right.
I found this code:
private Bitmap CombineImages(params Image[] images)
{
int width = 0;
for (int i = 0; i < images.Length; i++)
width += images[i].Width + 3;
int height = 0;
for (int i = 0; i < images.Length; i++)
{
if (images[i].Height > height)
height = images[i].Height;
}
int nIndex = 0;
Bitmap fullImage = new Bitmap(width, height);
Graphics g = Graphics.FromImage(fullImage);
g.Clear(SystemColors.AppWorkspace);
foreach (Image img in images)
{
if (nIndex == 0)
{
g.DrawImage(img, new Point(0, 0));
nIndex++;
width = img.Width;
}
else
{
g.DrawImage(img, new Point(width, 0));
width += img.Width;
}
}
return fullImage;
//img3.Save(finalImage, System.Drawing.Imaging.ImageFormat.Jpeg);
//img3.Dispose();
//imageLocation.Image = Image.FromFile(finalImage);
}
from this link http://www.codeproject.com/Articles/502249/Combineplusseveralplusimagesplustoplusformplusaplu

Drawing multiple lines with DrawLines and DrawLine produces different result

I am trying to draw multiple lines on a winforms panel using it's graphics object in paint event. I am actually drawing a number of lines joining given points. So, first of all I did this,
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawLines(new Pen(new SolidBrush(Color.Crimson), 3), PointFs.ToArray());
float width = 10;
float height = 10;
var circleBrush = new SolidBrush(Color.Crimson);
foreach (var point in PointFs)
{
float rectangleX = point.X - width / 2;
float rectangleY = point.Y - height / 2;
var r = new RectangleF(rectangleX, rectangleY, width, height);
e.Graphics.FillEllipse(circleBrush, r);
}
}
Which produces a result like the image below,
As you can see lines are drawn with having a little bit of extension at sharp turns, which is not expected. So, I changed the drawlines code to,
var pen = new Pen(new SolidBrush(Color.Crimson), 3);
for (int i = 1; i < PointFs.Count; i++)
{
e.Graphics.DrawLine(pen, PointFs[i - 1], PointFs[i]);
}
And now the drawing works fine.
Can anyone tell the difference between the two approaches?
I have just had the same problem (stumbled upon this question during my research), but I have now found the solution.
The problem is caused by the LineJoin property on the Pen used. This DevX page explains the different LineJoin types (see Figure 1 for illustrations). It seems that Miter is the default type, and that causes the "overshoot" when you have sharp angles.
I solved my problem by setting the LineJoin property to Bevel:
var pen = new Pen(new SolidBrush(Color.Crimson), 3);
pen.LineJoin = Drawing2D.LineJoin.Bevel;
Now DrawLines no longer overshoot the points.

WP7 Silverlight grid not showing content

It's been 2 hours of struggle against SL grid on WP7. I build my grid using the following code:
public void initUIBoard() {
int x, y;
Button b;
for (x = 0; x < mine.cRows; x++) {
RowDefinition rd = new RowDefinition();
rd.Height = new GridLength(20);
uiBoard.RowDefinitions.Add(rd);
}
for (y = 0; y < mine.cColumns; y++) {
ColumnDefinition cd = new ColumnDefinition();
cd.Width = new GridLength(20);
uiBoard.ColumnDefinitions.Add(cd);
}
for (x = 0; x < mine.cRows; x++)
for (y = 0; y < mine.cColumns; y++)
{
b = new Button();
b.Click += new RoutedEventHandler(this.caseClick);
b.Tag = mine.gameBoard[x][y];
Grid.SetRow(b, x);
Grid.SetColumn(b, y);
uiBoard.Children.Add(b);
}
}
The thing is, my grid is shown empty, am I doing something wrong with these Rows/Columns definition or something ?
Thanks in advance
After some experimentation, it looks like GridLength isn't calculating heights in pixels correctly.
Because the grid cell created isn't large enough the control is not shown.
Try increasing the sizes used for grid length. I did the following and got some output.
rd.Height = new GridLength(40);
Alternatively, consider setting the Heights and Widths to by dynamically sized. e.g.:
rd.Height = new GridLength(1, GridUnitType.Auto);
If you can investigate this height issue some more and also find it to be a height issue bug then please submit it to Microsoft.
Your code seems to work fine (I tried on Silverlight non-Winphone, but should be the same).
My guess is that the cause is somewhere else, for ex. another element covering the uiBoard grid, or the buttons being transparent with no background color/border.

How do you determine the width of the text in a WPF TreeViewItem at run time?

How do you determine the width of the text in a WPF TreeViewItem at run time?
I need to calculate an offset so I can draw a line from one leaf to the leaf of a different TreeView. All the 'width' properties return a size that is way bigger than the space taken up by the actual text of the node. It must be possible because the Select feature doesn't highlight the entire row. I'm writing the client in WPF and Silverlight.
You weren't very specific on the text or the tags, so I'm assuming you're taking about the .Net Framework's TreeViewItem.
There might be easier ways, but one possibility is to use the Graphics.MeasureString method. It gives you the size in pixels of a text when drawn using a specific font.
#mrphil: Sweet aborted fetus, that's scary
myTreeViewItem.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
Size s = myTreeViewItem.DesiredSize;
return s.Width;
I have two solutions:
A) Uses the visual tree
TreeViewItem selected = (TreeViewItem)dataSourceTreeView.SelectedItem;
double textWidth = 0;
double expanderWidth = 0;
Grid grid = (Grid)VisualTreeHelper.GetChild(selected, 0);
ToggleButton toggleButton = (ToggleButton)VisualTreeHelper.GetChild(grid, 0);
expanderWidth = toggleButton.ActualWidth;
Border bd = (Border)VisualTreeHelper.GetChild(grid, 1);
textWidth = bd.ActualWidth;
B) If you don't want to use the visual tree
TreeViewItem selected = (TreeViewItem)dataSourceTreeView.SelectedItem;
double textWidth = 0;
Typeface typeface = new Typeface(selected.FontFamily,
selected.FontStyle, selected.FontWeight, selected.FontStretch);
GlyphTypeface glyphTypeface;
if (!typeface.TryGetGlyphTypeface(out glyphTypeface))
throw new InvalidOperationException("No glyphtypeface found");
string headerText = (string)selected.Header;
double size = selected.FontSize;
ushort[] glyphIndexes = new ushort[headerText.Length];
double[] advanceWidths = new double[headerText.Length];
for (int n = 0; n < headerText.Length; n++)
{
ushort glyphIndex = glyphTypeface.CharacterToGlyphMap[headerText[n]];
glyphIndexes[n] = glyphIndex;
double width = glyphTypeface.AdvanceWidths[glyphIndex] * size;
advanceWidths[n] = width;
textWidth += width;
}

Resources