Trouble updating the margin property of buttons to animate them - c#

I have a WP8 app where I display buttons on a wheel. When clicked, I want the wheel to turn and bring the clicked button on the top of it.
I'm placing the buttons with their margin property. I figured I'd use a double while loop to move the buttons along the circle degree by degree, like this (trying to simplify it as much as I can) :
private void Select(Button selectedButton)
{
Button[] SelectedButtons = { button1, button2, button3 };
//Calculates the distance between buttons in degrees
double buttonDistance = 360 / SelectedButtons.Length;
double angleDeg;
double angleRad;
int i = 0;
int j = 0;
//While the selected button hasn't reach top position, move the wheel
while (selectedButton.Margin != new Thickness(<top position of the wheel>)
{
//Moves the buttons of a single degree
while (i < SelectedButtons.Length)
{
//Calculates the position of the current button in the array in degrees and converts it in radians
angleDeg = j + 90 + i * buttonDistance;
angleRad = Math.PI * angleDeg / 180;
//Button positioning
SelectedButtons[i].Margin = new Thickness(<calculation of the margins with the given angles>);
i++;
}
System.Threading.Thread.Sleep(5);
j++;
i = 0;
}
}
However, and even with the Sleep() function, the buttons' positions only update once the loop is over, and don't animate like I want them too.
I tried to use UpdateLayout() in the loop, both on the ContentPanel and on the Buttons themselves, I tried InvalidateArrange() and InvalidateMeasure(), or even adding a canvas in, but nothing does it : the buttons only update when the whiles are over, never before.
Can you guys please help me on this ?

Quick update, for anyone who could stumble upon the same issue :
Indeed, as steveg89 said, you can't update UIElements right from the GUI thread. The link he gave suggests using a background worker, or delegates, to get it to work. Unfortunately, WP8 doesn't allow it either.
The only solution is switching to storyboard animations : http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj206955(v=vs.105).aspx
Not extremely easy for a absolute beginner, but it works fine when you take the time to understand how these work and their different types (simple animations, keyframe animations, or path animations (however path animations are not supported in Windows Phone. Lost quite a bit of time to it.))

Related

How to align UI popup panel to Button's edge?

I have a "Screen Space - Camera" Canvas in Unity with several buttons inside. When I click a button, it opens a popup (UI Panel), outside of the button's parent, which I want to align to the specific button I pressed. I can position it over the button by simply matching its "rectTransform.position" to the button's rectTransform.position, but that just centers it over the button. I want its edge to line up with the edge of the button's edge.
I tried to get the width of the button and the width of the popup and then just shift it over by the width / 2, but the problem is the values are way off because of the type of canvas I'm using (I'm assuming that's issue). I can't change the canvas type for my game. I tried using Canvas.scaleFactor too, but it doesn't seem to work or I don't know how to use it.
The other big issue is that the button is deep down in the Canvas's hierarchy, but the popup is a direct child of the Canvas.
Here's what I tried so far:
// Popup position & size
RectTransform popupPOS = popupCanvas.transform.GetComponent<RectTransform>();
float popupRealWidth = popupPOS.rect.width * mainCanvas.scaleFactor;
// Button position & size
RectTransform btnPOS = gameObject.GetComponent<RectTransform>();
float btnRealWidth = btnPOS.rect.width * mainCanvas.scaleFactor;
// Position popup to position of button
popupCanvas.gameObject.GetComponent<RectTransform>().position = new Vector3(btnPOS.position.x, btnPOS.position.y, btnPOS.position.z);
// Move Rect.x by "RealWidth"
popupPOS.localPosition = new Vector3(popupPOS.localPosition.x + popupRealWidth / 2, popupPOS.localPosition.y, popupPOS.localPosition.z);
I found a solution. Here it is in case anyone is trying to figure this out in the future.
There was no need to use "scaleFactor". I feel like I tried this before and it didn't work. Maybe it's because I didn't follow the "PEMDAS" rule...sigh. My high school math teacher would be shaking her head.
popupPos.localPosition = new Vector3(popupPos.localPosition.x + (popupPos.rect.width / 2) + (btnPos.rect.width / 2), popupPos.localPosition.y - (popupPos.rect.height / 2) + (btnPos.rect.height / 2), popupPos.localPosition.z);
This aligns the popup (ui panel) to the top right of the button.
this.Parent = gameObject; //Or whatever your button is named
this.StartPosition = FormStartPosition.CenterParent;
I believe this is what you are looking for.

Anchoring with many TextBox controls

I am working on a science fair project and I really need to move forward beyond anchors. I have worked for a couple of days on anchoring this window and I cannot figure out how to resize all of these well.
Can somebody label this image with anchors and explain exactly how they work in a way that will make sense to a 12 year old?
I have marked the necessary Anchors in colors
You will need a little code in addition to the anchors, since Anchors can't handle more than one control in relation to the borders of its parent. In your layout you have three groupBoxes all (presumably) sharing the center of the form.. You could calculate dist if you want to, too..
Here is a piece of code to get you started with the GroupBoxes:
private void Form1_Resize(object sender, EventArgs e)
{
int dist = 3; // set to the distance between the GroupBoxes!
int width = (oneWideTextBox.Width - dist * 2) / 3;
groupBox1.Width = width ;
groupBox2.Left = groupBox1.Right + dist;
groupBox2.Width = groupBox1.Width;
groupBox3.Left = groupBox2.Right + dist;
groupBox3.Width = groupBox1.Width;
}
Of course I have made some assumptions about how you want it to work.. I hope you can take it from here! Feel free to ask!!

Simulate Mouse Drag Programmatically

I have a Windows Forms application with a control. The control consists of a chart panel with a canvas on which I paint. What I would like to do is to programmatically mouse drag the panel so that I have a specific distance between the right edge of the canvas and the last item painted on the canvas. I have tried two approaches. The both work in the sense that the panel is dragged as desired BUT I cannot seem to be able to get the precision of movement I desire. I coded a mouse simulator and have tried two approaches.
Approach 1:
if(this.ChartControl.ChartPanel.CanFocus)
{
// ... Focus the chart panel to be adjusted.
this.ChartControl.ChartPanel.Focus();
// ... Move cursor to lastBarScreenCoordinates on the chart panel to be adjusted.
Cursor.Position = new Point(lastBarScreenCoordinates.X, lastBarScreenCoordinates.Y);
MouseSimulator.SetMouseDragThresholds();
// ... Move chart panel to required position.
MouseSimulator.LeftMouseButtonDown(lastBarScreenCoordinates.X, lastBarScreenCoordinates.Y);
MouseSimulator.MouseMove(lastBarScreenCoordinates.X-positionShift,
lastBarScreenCoordinates.Y);
MouseSimulator.LeftMouseButtonUp(lastBarScreenCoordinates.X-positionShift,
lastBarScreenCoordinates.Y);
MouseSimulator.ResetMouseDragThresholds(_cx_default, _cy_default);
// ... Redraw the chart panel.
this.ChartControl.ChartPanel.Refresh();
// ... Reset cursor to its starting position.
Cursor.Position = new Point(startingCursorX, startingCursorY);
}
Approach 2:
if(this.ChartControl.ChartPanel.CanFocus)
{
// ... Focus the chart panel to be adjusted.
this.ChartControl.ChartPanel.Focus();
// ... Move cursor to lastBarScreenCoordinates on the chart panel to be adjusted.
Cursor.Position = new Point(lastBarScreenCoordinates.X, lastBarScreenCoordinates.Y);
MouseSimulator.SetMouseDragThresholds();
// ... Move chart panel to required position.
MouseSimulator.LeftMouseButtonDown(lastBarScreenCoordinates.X, lastBarScreenCoordinates.Y);
Cursor.Position = new Point(lastBarScreenCoordinates.X-positionShift,
lastBarScreenCoordinates.Y);
WindowsCommunication.SendMessage(this.ChartControl.Handle, 0x200, IntPtr.Zero,IntPtr.Zero);
MouseSimulator.LeftMouseButtonUp(lastBarScreenCoordinates.X-positionShift,
lastBarScreenCoordinates.Y);
MouseSimulator.ResetMouseDragThresholds(_cx_default, _cy_default);
// ... Redraw the chart panel.
this.ChartControl.ChartPanel.Refresh();
// ... Reset cursor to its starting position.
Cursor.Position = new Point(startingCursorX, startingCursorY);
}
I am using SendInput for simulating mouse clicks. Here is sample left mouse button down code ...
public static void LeftMouseButtonDown(int x, int y)
{
INPUT mouseInput = new INPUT();
mouseInput.type = SendInputEventType.InputMouse;
mouseInput.mkhi.mi.dx = CalculateAbsoluteCoordinateX(x);
mouseInput.mkhi.mi.dy = CalculateAbsoluteCoordinateY(y);
mouseInput.mkhi.mi.mouseData = 0;
mouseInput.mkhi.mi.time = 0;
mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTDOWN;
SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT()));
}
And I calculate normalized absolute coordinates for the mouse as follows ...
private static int CalculateAbsoluteCoordinateX(int x)
{
return ((x * 65536) + GetSystemMetrics(SystemMetric.SM_CXSCREEN) - 1) /
GetSystemMetrics(SystemMetric.SM_CXSCREEN);
}
So here are the precision issues. If I use Approach 1 (mouse move), the measured distance between the last item painted and the right edge of the canvas is different from what I set in positionShift and the cursor position difference does not equal positionShift. I initially thought it was due to pointer ballistics issues so I tried using Approach 2. Approach 2 does give me precision in pointer positioning but I am still having difficulty in that the panel moves but the distance between the last bar painted and the right edge of the canvas does not equal the positionShift amount as it should. It always seems to be off. I have been working on this for a long time now and am at my wits end. I am not sure what is going on here. How to improve the precision in my canvas drag by simulated mouse drag?
Well what you can do is this, First of all I believe the SendInput API allows for an AbsoluteValue flag so there is no need to calculate those values which may be the issue but most likely not.
Although I am curious as to why you are using a Mouse Drag opperation for this. It seems like all you want to do is reposition the canvas on every draw by some specified amount. if this is the case why not just set it explicitly on the canvas itself. Also it is unclear if you are using pure WinForms or WPF. The unclear bit being Canvas which I am fairly certain is only usable with WPF enabled windows.
That being said
WPF fix,
Depending on the Object containing the canvas just set its margin appropriately for the situation, since I do not know the data you are working with I cant say much about that. But this is a relatively simple idea so let me know if that works, it should give you, at least close too, a pixel perfect alignment.
WinForms,
Just do the above for the "Canvas" object you were talking about, or use absolute coordinates of the object to move it around.
If you could supply a sample of what you were working on looked like roughly maybe we could have a better idea of what you mean.

Is there an easy way to make a ScrollViewer "bouncy"?

Im using a WPF ScrollViewer to host some controls. I'd really like it to interact like on a touch device where it slowly eases back into place when you pull it too far.
It doesn't have a scrollbar - I have manual mouse scrolling with click and drag using this code:
Point currentPoint = e.GetPosition(this);
// Determine the new amount to scroll.
Point delta = new Point(scrollStartPoint.X - currentPoint.X, scrollStartPoint.Y - currentPoint.Y);
if (Math.Abs(delta.X) < PixelsToMoveToBeConsideredScroll &&
Math.Abs(delta.Y) < PixelsToMoveToBeConsideredScroll)
return;
scrollTarget.X = scrollStartOffset.X + delta.X;
scrollTarget.Y = scrollStartOffset.Y + delta.Y;
// Scroll to the new position.
sv.ScrollToHorizontalOffset(scrollTarget.X);
sv.ScrollToVerticalOffset(scrollTarget.Y);
Is there an easy way to do this? Currently it just acts like a normal scrolling textbox and will neither pull outside its normal range, nor slowly ease back.
If you are working on a Touch device, look at the Microsoft SurfaceScrollViewer (http://msdn.microsoft.com/en-us/library/microsoft.surface.presentation.controls.surfacescrollviewer.aspx). It already has this behaviour built in.
Getting Touch interaction right is tricky, easier to find someone else who's already done it. ;-)

Constraining windows wpf

I have a window that needs to be constrained within another window. In order to do this,
I hook into the SizeChanged event on the top level window....and in that event I need to adjust the second window so that it is aligned to the nearest edge only if there is an intersection between the two i.e if the smaller window gets outside the boundary of the bigger window.
I do a lot of math calculation to get this...and im still not near to the solution!
Im having trouble doing this because it involves a lot of messy code I was wondering if any of you guys had an easier solution to this?
Basically im dealing with 2 rectangles and I need to ensure that when the size of the bigger rectangle changes...if there is an intersection between the two, then the smaller rectangle should align itself to the edge of the bigger rectangle so that the smaller rectangle is within the bigger rectangle.
Could be a simple math problem in C# forms?
Any suggestions are welcome thanks!
For both windows you need to get the x and the y coordinates of the location of the window in systemcoordinates.
How to do this in wpf can be found here http://blogs.msdn.com/b/llobo/archive/2006/05/02/code-for-getting-screen-relative-position-in-wpf.aspx
Next you need to have the two windows react on each others sizechanged events so that the one window gets notified when the others size has changed.
Then the following math will do the job:
(assuming window 1 is currently in the bounds of window 2 and window 2 size changes and you want to actually resize the window instead of moving it when possible)
//PSEUDOCODE
//Case1 (left bound changes)
if(window2.x > window1.x)
{
window1.x = window2.x;
}
//Case2 (top bound changes)
if(window2.y > window1.y)
{
window1.y = window2.y;
}
//Case3 (right bound changes)
if(window2.x + window2.width < window1.x + window1.width)
{
window1.width = window2.x + window2.width - window1.x;
}
//Case4 (bottom bound changes)
if(window2.y + window2.height < window1.y + window1.height)
{
window1.height = window2.y + window2.height - window1.y;
}

Categories