I'm having a minor issue with my current app, dealing with visual states and automatic / static widths.
Depending on the visual state, a StackPanel either has a width="Auto" or width="400". Blend is telling me I can't animate between these two values (and I'm not really animating here, but simply switching between a fullscreen video and a composite view). Now I have to do an explicit test and change the width when I change my Visual State (through the VisualStateManager-framework. Is there any way I can do this in XAML (through the storyboards) instead of in the codebehind?
Some code samples of what I'm doing today:
private void Trailer_OnFullScreenToggled(object sender, EventArgs e)
{
var state = (Trailer.IsFullScreen() ? "Windowed" : "Fullscreen");
// HACK: Done to get past the auto / px issue
VisualsGrid.Width = Trailer.IsFullScreen() ? 400.0 : Double.NaN;
VisualStateManager.GoToState(this, state, true);
}
Any help would be greatly appreciated!
The "Auto" value for width is aliased to Double.NaN. This is why the animation fails -- it can't do interpolation to or from that value.
Have you tried using a keyframe animation with a discrete keyframe? Using a discrete keyframe animation should get around the problem that the animation system can't interpolate to or from Double.NaN since no interpolation will happen.
I'm not in front of a development environment at the moment, so I'm not sure if you would need to use a DoubleAnimationUsingKeyFrames with a DiscreteDoubleKeyFrame and a value of Double.NaN or a StringAnimationUsingKeyFrames with a DiscreteStringKeyFrame and a value of Auto.
That, of course, will not do a smooth animation from a fixed width to auto-sizing but instead will pop between the two.
Related
I want to create a plot that dynamically displays active elements as rectangles. I have achieved a first version that is actually ok using OxyPlot.Annotations.RectangleAnnotation which I add to myPlotModel.Annotations, you can see it in the image hereafter:
Example of wanted display
The thing is that after a while, the amount of drawn rectangles make the update not smooth as I update the shown timewindow (which is set to 15 seconds). I have already set a maximum of drawn elements that suffice to cover the displayed window (i.e. the rectangles get removed as they are too far in the past), but the rendering is still jerky. I draw the rectangles by allocating them to an equal fraction of the Y-axis, that is the third one from the top gets:
rowNumber= 3.0
minimumY = maximalY - maximalY / totalElements * rowNumber
maximumY = maximalY - maximalY / totalElements * (rowNumber + 1.0)
And the Y-axis is hidden.
My question:
Is there a smarter way of creating such a display that would be less computationally heavy, and therefore allow a smoother update? I do not have to stick to OxyPlot, it is simply the easiest way that I found to obtain what I wanted.
Thanks for your answers!
Technically, the answer to your question is "Yes".
There are a number of ways to do this.
You could have a vertical itemscontrol that had an itemscontrol in it's template. That could have a canvas as it's itemspresenter and you could bind canvas.top and canvas.left to properties in it's content. Template each into a rectangle and bind height and width.
And of course do something about the scale on the bottom and the column of activity labels or whatever you want to call them there.
Unless you're using an absolutely ancient machine, that'd just fly.
It's quite a lot of work but it would probably be quicker to write that than to search through a load of alternative packages and decide which was optimal.
I have two different grids, one stacked up on another. Now I am trying to reduce the size of the first grid(using visual layer animations), such that the other grid now takes up all the space.
ScalarKeyFrameAnimation animation1 = compositor.CreateScalarKeyFrameAnimation();
animation1.InsertKeyFrame(1.0f, 0);
animation1.Duration = TimeSpan.FromMilliseconds(300);
visual.StartAnimation(nameof(visual.Scale) + "." + nameof(visual.Scale.Y), animation1);
I have tried manipulating both offsets and scale property but none are able to change the actual height of the grid. As a result, the second grid doesn't move from its place.
Above is the live visual tree values, the actual height is not being affected with either scale or offset animation. And no "second grid" taking up entire space animation is happening.
ActualHeight & ActualWidth are values set by the layout engine.
VisualLayer animations and RenderTransform animations in XAML apply after the Layout passes and won't update affect ANY layout properties. They are, for lack of a better word, "Render time" properties. Any changes to them will not affect any layout other object.
If you'd really like this to work, you'd need to use either a LayoutTransform or animate the Width & Height of the object if they have one set using Storyboards. Noting however, this will cause animations to run on the UI thread because they require the Layout engine to re-run passes every frame, which will reduce performance.
I've put a TextBlock in a 3D panel (Planerator) and I used a Storyboard to animate it. (as crawl text)
When the field of view is 1 everything works fine, But if I set the field of view to more than 50 the frame rate will drop sharply and rendering will be choppy.
I used theCompositionTarget.rendering.
Please see the following images:
I need to 2D animations in 3d view with good performance.
Please tell me how can I solve this problem? Should I leave WPF and go to the DirectX?
UPDATE 1 :
I just want to move ONE 2Dtext in 3D space , but the performance is poor.(rendering isn't smooth it is choppy)
This is a sample project.
UPDATE 2:
This is the sample project updated version based on cokeman19's answer. (the performance have been improved ~10 frames, But I need to perfect rendering)
UPDATE 3 :
Finally, I got an acceptable performance with the help of the cokeman19's answer and the contents of this page.
I'm not sure if it's just a byproduct of the sample app, but under Planerator.CreateVisualChild(), it doesn't seem to be necessary to set the GeometryModel3D.BackMaterial. For reference:
VisualBrush vb = new VisualBrush(_logicalChild);
SetCachingForObject(vb); // big perf wins by caching!!
Material backMaterial = new DiffuseMaterial(vb);
...
GeometryModel3D backModel = new GeometryModel3D() { ..., BackMaterial = backMaterial };
The BackMaterial is a VisualBrush wrapper around the logical child, which doesn't belong to the visual tree, so rendering doesn't seem to make sense here. Moreover, the logical child (the LayoutInvalidationCatcher class), is in turn a wrapper around the visual child, which is already rendered (using _logicalChild) in setting frontModel.Visual.
Removing the code for the creation and setting of BackMaterial brings the FPS up to ~55.
In addition, if it's an option, setting the following brings the FPS back up to 60, with no noticeable degradation in quality.
RenderOptions.SetEdgeMode(_viewport3d, EdgeMode.Aliased);
Update:
The only other gain I was able to make was to set the CacheMode to BitmapCache, which may not be appliable for your needs.
frontModel.CacheMode = new BitmapCache(20) { EnableClearType = false };
Even on my slowest machine, this allowed for maximum FPS, but there are some drawbacks. Because the zoom level is so high on the text element, and this technique creates a picture to use in the animation (instead of animating the UIElement itself), I had to set the scale level to 20 before it became almost visually imperceptible. This of course has memory implications, as well.
Here is the problem that has been with me for the past several days. I have 10000+ Line objects on a Canvas and a Slider that I use to scale the canvas to create a zoom effect.
Everything is OK and the performance is great.
The only thing that bothers me is that the StrokeThickness of the Line gets scaled too. I tried to Bind the StrokeThickness to the inverse of the slider's value so that I get a uniform thickness whenever I move the slider. This worked but has decreased the performance substantially.
Is there any other way that would be suitable to this situation. I want to have a zero-width line thickness no matter how far I scale the canvas (like in CAD programs).
For the effect you want to achieve, overriding the StrokeThickness doesn't really mean anything as the it's value actually remains the same even if the ScaleTransform is changed.
The approach that you tried - Bind the StrokeThickness to the inverse of the slider's value - seems to be the most plausible one. To improve performance, instead of setting the StrokeThickness directly to inverse of Slider's value, set it to another property on your view model.
Then, in the event where sliding is completed, set the value of that property to the inverse of StrokeThickness.
Example -
private void OnSlidingComplete(object sender, EventArgs e)
{
LineStrokeThickness = GetInverseOfZoomValue();
}
I know that this is not exactly a solution, rather a workaround.
Ok, so I found some rather weird behaviour while messing around with the WPF ProgressBar control. This control is located in a column of a ListView control and the general situation differs little from this question & answer in its essence.
I bind Progressbar to a class by means of several properties (Min, Max, Value), all OneWay Bindings obviously. This other class is updated from another thread and regularly uses the INotifyPropertyChanged interface to let the ProgressBar know the status is progressing. And this all works just great!
But here is where it gets odd. My ProgressBar loses its glow.. right upto the moment it reaches the Max (=100%) value. Then it suddenly starts pulsing its white glowy stuff all over the green bar, and this is very annoying. I am showing progress with a reason, and the lack of a pulse is actually pretty distracting once you start to notice it not being there.
Thus, I set off to debug. I found that with Thread.Sleep(1000) in my threads processing, it still hid the glow, but if I bump it to Thread.Sleep(1500) the glow comes back at all times with a crazy vigour. After that, I tried translating my progress units to smaller numbers so the integer values would take longer to change. Min 0, Max 100 still has the lack of the glow. Min 0, Max 10 had the glow come back in its full vigor. In all cases, it is the same amount of work and time spent to reach 100%, but it is a very visible binary YES/NO effect with regards to the glow showing. The only thing I have not tested is whether it also happens when the ProgressBar is not placed inside of this ListView control.
I know myself well enough that I can't make sense of the deep WPF innards of the (XAML involved with the) ProgressBar control. So I was hoping anyone here knows whether this is a known bug, something they stumbled into, or something they might even know how to work around/fix.
My machine runs Windows 7, and I'm developing in VS2010 targeting .NET Framework 4 Client Profile.
I would take a guess and say that you lose the glow because you are updating your progress bar to often. Every time you set a new value the progress bar restarts its glowing animation (I think - I haven't tested this, I'm writing off the top of my head).
It seems that you have perhaps thought of the same thing and tried to work around it, but I'm not sure you have fully exhausted all possibilities:
Try creating a check that if (progressbar.Value == newValue) don't do progressbar.Value = newValue;
Progressbar should be using Decimals for Min, Max, Value. Make sure you don't do updates for every decimal point, eg. - 10,1; 10,2; 10,3; etc... (use progressbar.Value = (int)newValue;)
Try setting the progressbar value in bigger increments, instead of increment = 1, use increment = 10;
You could try taking a progressbar outside of ListView, maybe there is a rendering bug with progressbar being inside it.
PS! If you update your progressbar very rapidly, then it is OK for the glow animation not to run. Remember that the glow animiation's purpose is only to show that the application is still running (machine hasn't frozen), despite the fact that the progress(bar) hasn't moved.
If the progress is moving quickly, then that on its own is a visual effect for the user, so there is no need to have the glow animation at that moment...