I have an Image control, generated in runtime. It renders correct size when displaying. But I can't get size of that element. Width and Height is NaN. ActualWidth and ActualHeight is always 0.0 and control never fires SizeChanged event.
I'm also generating TextBoxes in the runtime and I can't get size of them too.
The code that generates image is bellow.
ExtendedImage image = new ExtendedImage();
image.Name = "element" + item.Id;
if (item.Text.ToUpperInvariant().EndsWith(".GIF"))
{
var gif = BookReader.Imaging.GIFDecoder.Decode(Application.GetResourceStream(new Uri("Files/Books/" + item.BookId + "/" + item.Text, UriKind.Relative)).Stream);
image.Source = gif.Frames[0].Image;
}
else
{
var img = new BitmapImage(new Uri("/Files/Books/" + item.BookId + "/" + item.Text, UriKind.Relative));
image.Source = img;
}
image.SetValue(Canvas.LeftProperty, (double)item.LocationX);
image.SetValue(Canvas.TopProperty, (double)(Application.Current.Host.Content.ActualHeight - item.LocationY));
image.SizeChanged += (o, e) =>
{
var sender = o as ExtendedImage;
image.SetValue(UIElement.RenderTransformOriginProperty, new Point(0.5, 0.5));
};
image.InvalidateMeasure();
if (!item.Visible)
{
image.Visibility = System.Windows.Visibility.Collapsed;
}
ContentPanel.Children.Add(image);
You can't access the size of the image before it's been rendered. And you can't render a item in a Canvas, without it having a explicit size.
So your problem is that you're attempting to get the size of the image before it's actually been rendered.
If the container of the Image has Height and Width, the image should have it as well. Try to put your Image into a Grid or StackPanel and set the size explicitly.
Related
I am trying to add different page contents in order to pass it to the Print Manager interface. However, when trying to add multiple BitmapImages, it's returning a "Element is already the child of another element." error.
Here's what my current code looks like:
Canvas page = new Canvas
{
Width = pageDescription.PageSize.Width,
Height = pageDescription.PageSize.Height
};
Canvas viewablePage = new Canvas()
{
Width = pageDescription.ViewablePageSize.Width,
Height = pageDescription.ViewablePageSize.Height
};
viewablePage.SetValue(Canvas.LeftProperty, pageDescription.Margin.Width);
viewablePage.SetValue(Canvas.TopProperty, pageDescription.Margin.Height);
// The image "frame" which also acts as a viewport
Grid photoView = new Grid
{
Width = pageDescription.PictureViewSize.Width,
Height = pageDescription.PictureViewSize.Height
};
The foreach loop wherein a different image is added to the a different page
foreach(var btm in bitmapImages)
{
Image image = new Image
{
Source = btm,
HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Center,
VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Center
};
// Use the real image size when croping or if the image is smaller then the target area (prevent a scale-up).
if ((btm.PixelWidth <= pageDescription.PictureViewSize.Width &&
btm.PixelHeight <= pageDescription.PictureViewSize.Height))
{
image.Stretch = Stretch.None;
image.Width = bitmap.PixelWidth;
image.Height = bitmap.PixelHeight;
}
photoView.Children.Add(image);
viewablePage.Children.Add(photoView);
page.Children.Add(viewablePage);
pages.Add(page);
}
bitmapImages is a list of bitmaps. It works if there's only one image to be added but when adding < 1 image to a page, it returns the error. Do you have any suggestions on how should I implement this?
Thanks alot.
Each UI element in UWP can only be used in the UI in one place at one time.
You need to define the UI element every loop.
foreach(var btm in bitmapImages)
{
Canvas page = new Canvas
{
Width = pageDescription.PageSize.Width,
Height = pageDescription.PageSize.Height
};
Canvas viewablePage = new Canvas()
{
Width = pageDescription.ViewablePageSize.Width,
Height = pageDescription.ViewablePageSize.Height
};
viewablePage.SetValue(Canvas.LeftProperty, pageDescription.Margin.Width);
viewablePage.SetValue(Canvas.TopProperty, pageDescription.Margin.Height);
// The image "frame" which also acts as a viewport
Grid photoView = new Grid
{
Width = pageDescription.PictureViewSize.Width,
Height = pageDescription.PictureViewSize.Height
};
Image image = new Image
{
Source = btm,
HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Center,
VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Center
};
// Use the real image size when croping or if the image is smaller then the target area (prevent a scale-up).
if ((btm.PixelWidth <= pageDescription.PictureViewSize.Width &&
btm.PixelHeight <= pageDescription.PictureViewSize.Height))
{
image.Stretch = Stretch.None;
image.Width = bitmap.PixelWidth;
image.Height = bitmap.PixelHeight;
}
photoView.Children.Add(image);
viewablePage.Children.Add(photoView);
page.Children.Add(viewablePage);
pages.Add(page);
}
I was able to add image to my panel with the following code,
But now my problem is I need to retrieve some information from the image etc(key value)
Is that possible to add in a value to every image?
foreach (System.Drawing.Image img in imagelist) {
PictureBox imagePicBox = new PictureBox();
imagePicBox.Name = "image" + imagePanel.Controls.Count.ToString();
imagePicBox.Image = img;
imagePicBox.Size = imagePicBox.Image.Size;
imagePicBox.BackColor = Color.Black;
imagePicBox.SizeMode = PictureBoxSizeMode.StretchImage;
imagePicBox.BorderStyle = BorderStyle.FixedSingle;
imagePanel.Controls.Add(imagePicBox);
}
You can use the Tag property of the System.Drawing.Image to add whatever data you want. this is what it's there for.
I have a BitmapImage that I want to get the PixelHeight and PixelWidth properties so I can determine whether it has a landscape or portrait layout. After I determine its layout, I need to set either the height or width of the image to get it to fit into my image viewer window without distorting the height:width ratio. However, it appears I have to call BeginInit() in order to do anything with my image. I have to call EndInit() to get the PixelHeight or PixelWidth properties and I cannot call BeginInit() more than once on the same BitmapImage object. So how can I possibly set my image, get the height and width, determine its orientation and then resize the image?
Here the chunk of code that I have been working with:
image.BeginInit();
Uri imagePath = new Uri(path + "\\" + die.Die.ImageID + "_" + blueTape + "_BF.BMP");
image.UriSource = imagePath;
//image.EndInit();
imageHeight = image.PixelHeight;
imageWidth = image.PixelWidth;
//image.BeginInit();
// If the image is taller than it is wide, limit the height of the image
// i.e. DML87s and all non-rotated AOI devices
if (imageHeight > imageWidth)
{
image.DecodePixelHeight = 357;
}
else
{
image.DecodePixelWidth = 475;
}
image.EndInit();
When I run this, I get this run-time exception:
InvalidOperationException:
BitmapImage initialization is not complete. Call the EndInit method to
complete the initialization.
Does anybody know how to deal with this issue?
As far as I know, what you want to do is not possible without decoding the bitmap twice.
I guess it would be a lot simpler to just decode the bitmap to its native size and then set the size of the containing Image control as needed. The bitmap is scaled appropriately, as Stretch is set to Uniform (since both width and height of the Image control are set, Stretch could as well be set to Fill or UniformToFill).
var bitmap = new BitmapImage(new Uri(...));
if (bitmap.Width > bitmap.Height)
{
image.Width = 475;
image.Height = image.Width * bitmap.Height / bitmap.Width;
}
else
{
image.Height = 475;
image.Width = image.Height * bitmap.Width / bitmap.Height;
}
image.Stretch = Stretch.Uniform;
image.Source = bitmap;
I have a ListView-derived class which creates a bunch of user controls that are Panel-derived classes that contain a few controls each, most importantly a Image control (m_labelIcon). I am setting the image source for this control dynamically to one of the PNGs in my resource:
Uri uri = new Uri("/MyApp;component/Common/Main/res/drawable/some_icon.png");
StreamResourceInfo resourceInfo = Application.GetResourceStream(uri);
BitmapImage bitmapSource = new BitmapImage();
bitmapSource.CreateOptions = BitmapCreateOptions.None;
bitmapSource.SetSource(resourceInfo.Stream);
m_labelIcon.Source = bitmapSource;
However, when the list view appears, the images are all missing. If I scroll the list to the very bottom and then back to the top, the images start appearing. I've specified BitmapCreateOptions.None, which should prevent delay-loading the images (they are in my resource and not on the web).
I've also tried using the ImageOpened event, but this doesn't work.
Any thoughts?
Thanks,
swine
After hours of the debugging, I stumbled upon the simple solution. Even though I was overriding ArrangeOverride() and MeasureOverride() like so:
protected override Size MeasureOverride(Size availableSize)
{
Size panelDesiredSize = new Size();
double height = Math.Max(getIconSizeToUseInPixels(),
m_labelName.DesiredSize.Height);
panelDesiredSize = new Size(availableSize.Width, height);
return panelDesiredSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
double x = 0;
double y = 0;
m_labelName.Measure(finalSize);
double iconWidth = getIconSizeToUseInPixels();
Size iconSize = new Size(iconWidth, iconWidth);
double nameWidth = m_labelName.DesiredSize.Width;
double nameHeight = m_labelName.DesiredSize.Height;
m_labelIcon.Arrange(new Rect(
new Point(x, y), iconSize));
m_labelName.Arrange(new Rect(
new Point(iconWidth, y + (finalSize.Height - nameHeight) / 2),
new Size(nameWidth, nameHeight)));
m_labelName.Width = nameWidth;
m_labelName.Height = nameHeight;
return finalSize; // Returns the final Arranged size
}
I still needed to set the Width and the Height properties of the Image control manually in the constructor of my custom control like so:
THIS FIXED THE PROBLEM:
m_labelIcon.Width = getIconSizeToUseInPixels();
m_labelIcon.Height = getIconSizeToUseInPixels();
I created an Image with this code
OpenFileDialog dlg = new OpenFileDialog();
dlg.FileName = ""; // Default file name
myImage = new Image();
try
{
Nullable<bool> result = dlg.ShowDialog();
if (result == true)
{
string sUri = #dlg.FileName;
Uri src = new Uri(sUri, UriKind.RelativeOrAbsolute);
BitmapImage bmp = new BitmapImage(src);
myImage.Source = bmp;
myImage.Width = 100;
myImage.Height = 100;
}
}
I can zoom in/out on this image
public void Scale(int i, Point center)
{
Matrix m = myImage.RenderTransform.Value;
if (i > 0)
m.ScaleAtPrepend(1.1, 1.1, center.X, center.Y);
else
m.ScaleAtPrepend(1 / 1.1, 1 / 1.1, center.X, center.Y);
myImage.RenderTransform = new MatrixTransform(m);
}
but when I get the ActualWidth or Width or ActualHeight/Height returns the number 100. this means that these changes not applied to origin image (myImage).
Now How to apply the changes (zoom or any changes) to origin Image?
Tanx all;
Transforms only affect the appearance / layout of the object they are applied to and won't make any changes directly to the source. For this you'll need to resize the image yourself, reading the values of the scaling and applying those to the original width and height.
Take a look at something like AForge.Net which has myriad methods for manipulating images allowing control over the quality of the transformation etc.