DoubleAnimation complains of origin == NaN only when resource is in Window - c#

I have a large WPF application. I'm looking to make the UI multithreaded. As part of that process, I'm moving some application-level control and style resources to the Window level. (I know from experience that I can't use DynamicResource and resolve at the application level unless I'm on the application thread.) Anyway, I moved a bunch of control resources. The application works find with one nasty problem: all of my animations on FrameworkElement Height and Width broke. They all fail because the control is of width or height NaN. These animations all work when the control templates are registered at the application level. All of my controls where I animate height or width have appropriate default height or width values that are not NaN. Why would the resource location affect this?

Use ActualWidth and ActualHeight. Nan means that these propeties are not set yet.
https://stackoverflow.com/a/607849/3955716

This is late, but in case someone else get into this.
the DoubleAnimation is a helper class that allows for a double to go from a value to another in a smooth fashion.
As you don't specify a Width explicitly for your grid, the default value is NaN.
Thus the DoubleAnimation is trying to go from NaN to Whatever the target value. This cannot be done for obvious reasons.
If you set the Width of the grid, it should work properly.
A workaround would be to set the grid width after it loads in the constructor :
public Grid()
{
InitializeComponent();
this.Loaded += (s, _) => this.Width = this.ActualWidth;
}
Hope this help.

Related

Responsive grid in Xamarin.forms

Referring to my previous question, I need some help making the listview items responsive on all the platform, all the sizes and also on landscape and portrait mode. The listview which I have now becomes tiny on a 10" screen. I would like to make it responsive. Any reference to achieve this?
It sounds like you have some kind of fixed width issue perhaps if your ListView is small and not covering the entire page?
On your mainList you are setting to the ContentPage without any layout options.
Try setting the HorizontalOptions and VerticalOptions of the outer element first, and once you get that working, focus on the inner controls to ensure they take up the desired amount of space afterwards.
o.HorizontalOptions = LayoutOptions.FillAndExpand;
o.VerticalOptions = LayoutOptions.FillAndExpand;
Change the ListView BackgroundColor to some noticeable color to help you ensuring that things are laying out correctly.
Every Xamarin.Forms.Element(and therefore every page) implements a Width and a Height property, you can use these to adjust your layout depending on Page-Size.
You should take a loot at this page regarding the VisualElement class https://developer.xamarin.com/api/type/Xamarin.Forms.VisualElement/
You could also use Device.Idiom to check if you are on a phone or Tablet and handle each case individually:
if (Device.Idiom == TargetIdiom.Phone)
//your code goes here
else
if (Device.Idiom == TargetIdiom.Tablet)
//your code goes here
else
throw new PlatformNotSupportedException();
For landscape/protrait simply check with the Width/Height-Properties of your page:
if (Width > Height)
{
//"landscape"
}
else
{
//"portrait"
}
For handling Orientation changes implement an Event-Handler for SizeChanged or simply overwrite OnSizeAllocated (https://developer.xamarin.com/api/member/Xamarin.Forms.VisualElement.OnSizeAllocated/p/System.Double/System.Double/)

How to get the height of the draggable bar in a scrollviewer?

I am trying to get the distance in pixel between the top of the control and the middle of my vertical scrollbar (not all the scrollviewer, only the bar you can drag to scroll the control).
I don't understand which property i should use.
This is the code i wrote:
double barHeight = /*to do*/;
double barUpperEdge = scrollViewer.VerticalOffset;
double distance = barUpperEdge + (barHeight/2);
Another question: which is the mesurament unit of scrollViewer.VerticalOffset? If it isn't in pixel what cast should i do?
You can calculate that value from the IScrollInfo Interface. The ScrollViewer Class implements this interface and exposes the relevant properties that you need to use. As far as I can remember, you need to utilise three properties:
ExtentHeight - Gets a value that contains the vertical size of the extent.
ViewportHeight - Gets a value that contains the vertical size of the content's viewport.
VerticalOffset - Gets a value that contains the vertical offset of the scrolled content.
To explain a little further, the viewport relates to the visible area of the ScrollViewer and the Extent represents the total size of the scrollable area. The VerticalOffset describes the amount that the scrollable content has been scrolled. Using these three values, you should be able to calculate your required values that relate to the ScrollBar. Try something like this:
double barHeight = ViewportHeight * scrollviewer.ActualHeight / ExtentHeight;
UPDATE >>>
Please note that it is generally bad practice to use constant values in your calculations. Microsoft have exposed many common properties for this very reason. In your case, I believe that you can make use of the SystemParameters.VerticalScrollBarButtonHeight property, although you may need to add something to accommodate Padding and/or Margin values:
double barHeight = ViewportHeight * (scrollviewer.ActualHeight - 2 *
SystemParameters.VerticalScrollBarButtonHeight) / ExtentHeight;
You know... I've just thought of something... you may even be able to get your required thumb Height from these SystemParameters... you could try the SystemParameters.VerticalScrollBarThumbHeight Property, although I don't think that it will work with custom ScrollBars.

How can I predict a XAML Label's height on a Canvas

I have an application where I need to dynamically build the content to a Canvas. Everything works just fine, but I am a little unsure of how I can set the y coordinates for the labels in the safest way. For example, I need to add three labels that are essentially lines of text. In Java Swing or C# GDI I would just query the the font for the line height and add that value to the y coordinate of the drawText command.
This is my code.
double y = 0.0;
_line1.Content = "Line1";
_line1.SetValue(Canvas.TopProperty, y);
_line1.SetValue(Canvas.LeftProperty, 0.0);
CanvasChart.Children.Add(_line1);
double textHeight = _line1.Height;
y += textHeight;
_line2.Content = "Line2";
_line2.SetValue(Canvas.TopProperty, 0.0);
_line2.SetValue(Canvas.LeftProperty, y);
CanvasChart.Children.Add(_line2);
This does not work because _line1.Height does not seem to be set to anything useful at this point. I suppose it has not rendered yet. The above code is in the loaded event for the window. ActualHeight does not help either.
Most code that I've seen seems to just set them to a hard coded value. That I suppose looks right on the developer's display, and you just hope looks good at other resolutions/DPI. In Swing and GDI I always had the best results finding out exactly how many pixels a string will be rendered at and using this to offset the next line.
You must call the Measure method, specifying an infinite available size. This will update the DesiredSize of the control:
_line1.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
double textHeight = _line1.DesiredSize.Height;
Another easy way to achieve the desired effect is to put the labels in a StackPanel.
In Swing and GDI I always had the best results finding out exactly how many pixels a string will be rendered at and using this to offset the next line.
This is possible in WPF as well. The GlyphTypeface class provides the AdvanceWidths and AdvanceHeights properties for each character in a typeface. By using CharacterToGlyphMap, you can map a character to an index within the AdvanceHeights, and use that to determine the actual height of any character.
For a detailed example, see GlyphRun and So Forth.

Resize Controls with Form Resize

I have read several stack overflow questions without finding a good working solution to my problem. How can I resize my controls whenever the form is resized? I would like them to get larger or smaller when the form becomes larger or smaller.
In visual basic this was quite easy to do with the form.Zoom property (which did't really require resizing controls of course, but solved what I needed). Unfortunately this is not available in C# winforms.
Here is some other things I have tried without luck:
private void formMain_Resize(object sender, EventArgs e)
{/*
double scale;
this.scaleWidth = (float)this.Width / (float)this.origWidth;
this.scaleHeight = (float)this.Height / (float)this.origHeight;
if (this.scaleHeight > this.scaleWidth)
{
scale = this.scaleHeight;
}
else
{
scale = this.scaleWidth;
}
foreach (Control control in this.Controls)
{
control.Height = (int)(control.Height * this.scaleHeight);
control.Width = (int)(control.Width * this.scaleWidth);
this.Refresh();
// control.Font = new Font("Verdana", control.Font.SizeInPoints * heightRatio * widthRatio);
}
///////This scaling didnt work for me either
//this.Scale(new SizeF(this.scaleWidth, this.scaleHeight));
//this.Refresh();
*/
}
If I overlooked an actualy working sample of code on another stack overflow question I would love to see it, but the ones I found were similar to those above which are not working.
Perhaps I was misusing it and someone could post sample code to show for those of us who keep asking this question how to go about solving the problem.
Also, I have tried using some of the anchor/docking tools thinking they would automatically allow it but it didn't.
The best option is to use a TableLayoutPanel. Put TableLayoutPanel on the form, set the Dock property to Fill, create required rows and columns and put the controls inside the cells. Of course you need to set Dock/Anchor on the controls inside the cells, so they respond to changes to the cell size. In some situations you may need to put a Panel into a cell and drop the controls inside it, because every cell can only contain a single control. You may also need to set RowSpan/ColumnSpan on the controls.
By using a TableLayoutPanel, you have complete control over how your cotrols should be arranged. You can set absolute or percentage size for rows and columns.
Use Anchor of the control. There's an option on anchoring the top, bottom, left and right. And you're good to go.
I found an alternative solution that is working well for me, appreciate any negative or positive comments on the solution.
Using several Split Containers and Split Containers inside of Split Containers in different regions I am able to section off the primary pieces of the layout, and within there utilizing Docking and Anchoring I am able to accomplish exactly what I wanted to do - it works beautifully.
I would point out I am aware that some folks online mention split containers use lots of resources.
If your controls are in a group box, be sure to set the group boxes properties to resize. Controls inside the box are controlled by the box. The box size (unless it is inside another box) is controlled by the form.
What you are trying to do in your code is to change the sizes of the controls which isn't so good approach. Generally, the size of the Buttons and TextBoxes shouldn't be changed when you re-size your form, but they often need to move (change location). Some controls do need to change size according to the re-sized form and but in most cases only one dimension. The central controls that are used for working area (if you are developing the tool for drawing for instance) should change sizes of both dimensions. All this you can accomplish by properly setting Dock and/or Anchor properties of the controls.
textBox1.Dock = DockStyle.Bottom;
textBox1.Anchor = AnchorStyles.Bottom & AnchorStyles.Left;
All these are also easily set in the Properties panel when using designer.
But if that isn't enough for you, in rare cases, you will most definitely want to only change the location of the control:
textBox1.Location = new Point(newX, newY);

Cannot modify expression because it is not a variable

I'm trying to get an UserControl (which has a grid on it) on a Windows Form to resize.
The below code is what I have in the Form. The behavior I'm getting is that the control is resized when I make it big. But it does not shrink. What am I doing wrong (or) What am I missing?
private void AdjustGrid()
{
ZoomControl.Location = new Point(5, 5);
ZoomControl.Size = new Size(this.Width - 15, this.Height - 75);
}
void zoomform_Resize(object sender, EventArgs e)
{
AdjustGrid();
}
Now the user control has the following code:
//Resize the grid that the UserControl has on it
private void NameValuePropertyBag_Resize(object sender, EventArgs e)
{
grdNameValueProperties.Location = new Point(4,4);
grdNameValueProperties.Size = new Size(this.Width - 8, this.Height - 8);
}
I tried
grdNameValueProperties.Size.Width = this.Width - 8;
grdNameValueProperties.Size.Height = this.Height -8;
It gives me "Cannot modify expression because it is not a variable" error... What am I missing?
Additional Info:
I'm using SetParent() Windows call to move/zoom an UserControl to another Form (ZoomForm).
Anchor doesn't seem to work for controls moved with SetParent()... More precisely, it may be working but I have repainting problems.
I got Anchor/Dock pair to working without repaint issues [I removed the resize event wireup and adjusted Dock to Fill]
The ZoomForm initally has no controls. The Usercontrol is added to the ParentForm dynamically.
Currently, I'm able to make the zoom form bigger with the above code but not smaller.
grdNameValueProperties.Size.Width = this.Width - 8;
grdNameValueProperties.Size.Height = this.Height - 8;
That code gives the error because Size is a value type, not a reference type. Reading this may help explain the difference between value types and reference types.
As recursive commented, you should just use the Anchor property.
The error occurse because the Size property exposes a struct and not a reference type. The Size property returns a copy of the size object of the control. Writing to the properties Width and Hight of this copy makes no sense because it is just a temporary copy and not backed by memory anywhere.
You can't directly change the Size.Width property on a UserControl, because the Size property is a value type, so changing its width would essentially be overwriting the entire Size property. Instead, controls in WinForms provide their own Width and Height properties, so this code should work:
grdNameValueProperties.Width = this.Width - 8;
grdNameValueProperties.Height = this.Height - 8;
Having said that, I agree with #recursive's comment that you should probably just use the UserControl's Anchor property to make it "automatically" resize.
Currently, I'm able to make the zoom form bigger with the above code but not smaller.
Some controls have a MinSize (or similar) property on them. Do you have any of those set such that you can't resize smaller?
For the first portion -
First off, I'd recommend using the Anchor property on UserControl instead of trying to size this yourself. It works very simply, and very reliably, for handling window resizing.
If you want to do this, you should probably look at chaining off this.ClientSize instead of this.Height and this.Width. You're probably setting your control too large, and that's unachoring the panel or other thing you're sitting on, which causes all sorts of issues.
The second part is due to the fact that gridNameValue Properties.Size.Width is a member of a struct.
When you call gridNameValueProperties.Size, you're returning a Size struct, then trying to set the Width on the returned struct (not the original). This is why you need to set the entire Size valuetype in one shot. Creating a new Size() and setting it to gridNameValueProperties.Size is the only way to make that work.

Categories

Resources