Resizing a grid control programatically over a period of time - c#

G'day,
I am attempting to simulate the old XBox 360 GUI with the sliding tabs (Remember, you'd press left or right and the content would slide in depending on the tab?) Anyways, at the moment, I have this working well, however I cannot get the "animation" working.
When the user presses left arrow or right arrow, my OpenWindow(int iIndex) method will be called, where iIndex is the index to the next or previous "window" to be slid in. (Not a window... each "Window" is a struct with a parent grid control containing a button and a smaller grid control that contains the windows contents.)
Now, my problem lies with resizing the parent grid control. When it is slid in, it is resized by calling mygrid.Width += 1; That works, but I don't see it happen over a determined period of time, it just lags a bit and then resizes to the required width. Whereas if I call this.Width += 1 in the same method, (this being the main program window) the window resizes how I want the grid control to resize. I've tried UpdateLayout() but to no avail. This tells me my timing is okay.
If anyone could be of assistance, it would be greatly appreciated.
Here is my OpenWindow method...
public void OpenWindow(int iIndex)
{
int iInterval = 1;
for (int i = (int)myDict[iIndex].Shell.Width; i < (int)stack_outter.Width; i += iInterval)
{
myDict[iIndex].Shell.Width += 1;
myDict[iIndex].Shell.UpdateLayout();
System.Threading.Thread.Sleep(1);
}
myDict[iIndex].Shell.Width = stack_outter.Width - (BUTTON_WIDTH * (myDict.Count - 1));
}
myDict is a Dictionary, Shell is the grid that I am attempting to animate when resizing. Sorry about the code, it's messy, my code is always hacked when I am trying to get stuff working :)
Thanks,
Ash
Neried Web Solutions

Your OpenWindow method is happening on the Dispatcher thread. That's also the thread responsible for rendering, so as long as your OpenWindow method doesn't return, nothing gets rendered.
The proper way to fix this would be to animate the Width property. I don't have any experience in starting animations from code (I've only used them in the past for things like a fade-in button highlight on mouse over, which is more easily done from WPF), but I took a quick read-through this page, Animation Overview on MSDN, and I think you'll want something like this:
DoubleAnimation myDoubleAnimation = new DoubleAnimation();
myDoubleAnimation.From = myDict[iIndex].Shell.Width;
myDoubleAnimation.To = stack_outter.Width;
myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(0.5));
myDoubleAnimation.AutoReverse = false;
myDoubleAnimation.RepeatBehavior = new RepeatBehavior(1.0);
myStoryboard = new Storyboard();
myStoryboard.Children.Add(myDoubleAnimation);
Storyboard.SetTarget(myDoubleAnimation, myDict[iIndex].Shell);
Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(FrameworkElement.WidthProperty));
myStoryboard.Begin(myDict[iIndex].Shell);

Related

C# WPF ScrollViewer scrolling locks a framerate at 30fps with a very low UI thread utilization percentage

I am very confused, I see that UI thread is almost not loaded, timeline profiling tells me that my fps should be at least equal to 60, but the real fps unstable.
So, I have two VirtualizingStackPanel, they both use a DoubleAnimation for smooth scrolling. The only one thing(that I know) they are different is that the first is created with xaml and is a ListView.ItemsPanelTemplate and is managed by ItemSource property of ListView; the second panel I created manually in code, manually set it as a Content of manually created ScrollViewer object and manually add every child to this panel.
The creation code:
private void InitializeItemsOwner()
{
ItemsOwner = new VirtualizingStackPanel
{
Width = this.Width,
Height = this.Height
};
VirtualizingPanel.SetIsVirtualizing(ItemsOwner, true);
VirtualizingPanel.SetCacheLengthUnit(ItemsOwner, VirtualizationCacheLengthUnit.Item);
VirtualizingPanel.SetCacheLength(ItemsOwner, new VirtualizationCacheLength(2));
VirtualizingPanel.SetVirtualizationMode(ItemsOwner, VirtualizationMode.Recycling);
UpdateFrameworkElement(ItemsOwner, RenderSize, new Rect(RenderSize));
PreviewMouseWheel += Managers.AnimationManager.ListView_PreviewMouseWheel;
}
private void InitializeScrollOwner()
{
ScrollOwner = new ScrollViewer()
{
VerticalScrollBarVisibility = ScrollBarVisibility.Disabled,
HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled
};
ScrollOwner.Content = ItemsOwner;
ScrollOwner.InvalidateScrollInfo();
UpdateFrameworkElement(ScrollOwner, RenderSize, new Rect(RenderSize));
this.Content = ScrollOwner;
}
/// <summary>
/// Updates layout of FrameworkElement object
/// </summary>
/// <param name="element">Framework element to update</param>
/// <param name="availableSize">Meashre with availableSize</param>
/// <param name="finalRect">Arrange with finalRect</param>
private void UpdateFrameworkElement(FrameworkElement element, Size availableSize, Rect finalRect)
{
element.Measure(availableSize);
element.Arrange(finalRect);
element.UpdateLayout();
}
Here is a Profiler screenshot which, I hope, shows all important info.
The first panel scrolling is at the left part of profiling screenshot, the second panel - at the right. We can see, that first panel loads UI thread much more because of a bit expensive layout and code operations, but it has a stable 60 fps; the second panel, which is created in code loads UI thread much less than the first panel scrolling, but nevertheless it drops a framerate down to 30 as it woulld be locked at 30 fps. I think it's very strange behaviour for such a simple. The important thing is that both the stackPanel objects has less than 40 children, I checked it in a Live Visual Tree window.
As I mentioned above I add children to the second panel in code, every child is an Image control with a Source property set. Here is a code of child adding method:
private void AddChild(BitmapSource image)
{
Image imageControl = new Image
{
Source = image,
SnapsToDevicePixels = true,
UseLayoutRounding = true
};
RenderOptions.SetBitmapScalingMode(imageControl, BitmapScalingMode.NearestNeighbor);
imageControl.Effect = new System.Windows.Media.Effects.DropShadowEffect()
{
Color = Colors.Black
};
imageControl.CacheMode = new BitmapCache();
Size imageSize = new Size(image.Width, image.Height);
ItemsOwner.Children.Add(imageControl);
UpdateFrameworkElement(imageControl, imageSize, new Rect(imageSize));
ItemsOwner.UpdateLayout();
}
So a very interesting thing for me is that if replace this Image control with some Rectangle any other simple control the lock at 30fps disappear and I have a smooth 60fps during scroll animation. The problem is in this Image control, arrangement of such instance is heavy for some reason, but why a Profiler doesn't tell anything about it? Could I miss something important with Image instance creation? If yes, what can I try to solve this problem?
Thank you, if you need some additional details please let me know. Waiting for your thoughts..
So, the problem is in DropShadowEffect. Arrangement of the second panel items cause their shadow effects to be recalculated/redrawn or something like that. So The solution is to get rid of DropShadowEffect at all, or you can use a RenderTargetBitmap to render the whole control with shadow effect to a BitmapSource object like it is described here. So the question is closed!

Unity3D draw GUI.Button over GUI.Window

I want to draw a GUI Button on top of a GUI window that I have in my game, but no matter what I try the button always appears behind.
This is my Code:
GUI.depth = -30;
Rect navBackButton = new Rect(10, 10, 10, 10);
// DRAW NAVIGATION BUTTONS
if (GUI.Button(navBackButton, navBackButtonTexture))
{
// DO LOGIC HERE
}
GUI.depth = 10;
topScrollRect = new Rect(0, 0, Screen.width, topScrollHeight);
topScrollListSize = new Vector2(topScrollRect.width - 2*listMargin.x, topScrollRect.height - 2*listMargin.y);
GUI.skin.window = topStyle;
GUI.Window(0, topScrollRect, (GUI.WindowFunction)DoTopScrollWindow, "");
I have tried to draw the buttons before drawing the window, and the other way round, but both have the same result.
In this forum post (http://forum.unity3d.com/threads/setting-depth-of-a-window.12554/), it says that any GUI control with a depth of less than 1 will appear in front of GUI Windows, but I have set my depth to -30 and still the button appears behind the Window.
Any suggestions would be greatly appreciated!
The way to do this is to draw the button in DoTopScrollWindow().
You shouldn't try to place the buttons "on top" of the window, you should put them "in" the window, as the window is your navigation button's parent, conceptually. Additionally, drawing them in the window means that you can take advantage of relative positioning and window resizing without having to write a lot of extra code.
According to the docs, the parameter func in GUI.Window() is a function designed to display content inside the window.
In this case you want your buttons "inside" that window, so draw them in the function you pass in as func.

Custom list, moving stuff up automatically after removal in Windows Phone

So im developing this app, where i got something that reminds alot about a list, but it doesn't use a list control or something. I add grids & rectangels to a scrollviewer, and when i doubletap a grip or a rectangel, it dissapears with a fade animation (which i also need help to do, as well as fade in, fast, one by one on app startup), and when that happens, i want the grid or rectangel beneath the one that faded out (or was removed, what is the best solution?), to be slided up, and replace the empty position. Please, do not misunderstand the question, i dont want you to make it for me, i want to know how since i absolutely cannot find ANY solution at all. It kind of works like google now for android and iphone. How can i do this the best way? Thank you SO much! Best regards, Erik
My DoubleAnimation to fade the grid:
DoubleAnimation fadeGrid = new DoubleAnimation();
fadeGrid.From = 0;
fadeGrid.To = 1;
fadeGrid.Duration = new Duration(TimeSpan.FromSeconds(0.5));
fadeGrid.AutoReverse = false;
1) Use animations for your fade out and slide up. For fade, you'll be doing a DoubleAnimation on the Opacity property. For sliding items up, you'll be doing an animiation on the TranslateTransform property. See these MSDN guides: http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj206955(v=vs.105).aspx and http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.windows.media.translatetransform(v=vs.105).aspx
2) For actually properly moving things up, you'll want to capture the Completed event from the animiation (http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.windows.media.animation.timeline.completed(v=vs.105).aspx). When the animiation completes, remove those controls from the StackPanel inside the ScrollViewer, and undo any position animation you did on the items below it to animate them 'sliding' up.
3) After creating an animiation, you need to add it to a storyboard:
Storyboard sb = new Storyboard();
sb.Children.Add(fadeGrid);
Storyboard.SetTarget(fadeGrid, myRectangle);
Storyboard.SetTargetProperty(fadeGrid, new PropertyPath("(UIElement.Opacity)"));
sb.Begin();
The syntax for the propertypath but not be quite perfect, but you get the idea. You can see another example that specifically mentions opacity here: http://blogs.msdn.com/b/silverlight_sdk/archive/2008/03/21/silverlight-animations-a-walkthrough.aspx

ScatterView item orientation and PrimarySurfaceDevice.Tilt

I'm working in Visual C# 2010 Express with WPF to develop an application for a Microsoft Surface table, and cannot for the life of me find the simple solution to this problem.
When using a ScatterView control without setting a custom template for scatterview items, the control throws new ScatterViewItems onto the screen at random orientations and positions. This, I like.
I am developing my program on a vertical screen, on which scatterViewItems are randomly thrown, except they are mostly upright, and never thrown on updide-down. What I am getting at is the control knows the screen is vertical and keeps the items from starting out upside down.
However, when I transfer the program to a device with a horizontal screen, the items are now thrown out randomly and OFTEN upside down from the original app orientation. Again the ScatterView control is reading InteractiveSurface.PrimarySurfaceDevice.Tilt (or something like it) and compensating.
How do I make it stop doing this?
I just want my items to continue to appear in the ScatterView as if the screen was vertical. Can I trick ScatterView into thinking it's vertical still? Can I turn this feature off? I would like to avoid making my own template for ScatterViewItems.
Thanks!
Set the Orientation property to 0 for each item. The randomness only happens when you haven't explicitly set a value
Well, if nobody can explain how ScatterView knows the screen tilt angle, and how to change that, then the only solution is to generate your own randomness. For reference, here's what I used to do this:
ScatterViewItem item = new ScatterViewItem();
item.Content = image;
Random rand = new Random();
item.Orientation = RandOrientation(-20, 20);
item.Center = RandCenter(50);
SSScatter.Items.Add(item);
private Point RandCenter(int pad)
{
int randx = rand.Next(pad, (int)SSScatter.Width-pad);
int randy = rand.Next(pad, (int)SSScatter.Height-pad);
return new Point(randx, randy);
}
private int RandOrientation(int low, int up)
{
int randor = rand.Next(low, up);
return randor;
}
I still wish there was a way to trick ScatterView...

Showing and hiding parts of winforms (extending?) C# .NET

I have a question about forms and controls. I want to add the ability to sort of make a part of my form only show when something is clicked. For example I have form1 and on the form i have a button and when that button is clicked the form grows or extends (slides out?) to show other controls that werent there before the button was clicked. I have no idea what this is called so I don't know what to look for but Ive seen it used in many other applications. Any information on this would be greatly appreciated.
You'd probably have to roll your own animation, increasing the size dimensions of your form (or panel, or whatever) on a timer, thereby exposing the previously hidden controls.
Timer T = new Timer();
T.Interval = 10;
T.Tick += (s, e) =>
{
myForm.Size = new System.Drawing.Size(myForm.Width + 10, myForm.Height);
if (myForm.Size.Width >= FormWidthThreashold)
T.Stop();
};
T.Start();
At the risk of stating the obvious, I don't suppose there's any way to switch the WPF? This stuff is built in, and quite easy for WPF. If not though, something like this should get you started.
I've done this before. Start by organising your form into logical sections. Don't leave all your controls on the form, place them inside panels. At Design-time you'll need to have the panels "fully expanded", but then at runtime you manipulate the panels' left, top, width, height, and maybe even the alignment and anchors properties, through code. You could use a timer as suggested by #Adam Rackis.. or you could change the increment value to alter the speed of the animation. The animation itself is just a loop that starts with x = x1 and ends with x = x2, where x = x + increment_value inside the loop. As the value of "x" changes, the component will be automatically redrawn. To get a smoother effect you might need to repaint the control (or the entire panel) on each iteration. If it runs too fast, you can either insert a delay or try to make the loop rely on a timer. I've had problems with timers for this kind of stuff, but admittedly I wasn't using C#.NET at the time (I did it in Delphi). It takes a lot of fiddling with the fine details to get this working nicely, so be patient, it's not Flash! Good luck.

Categories

Resources