I want to do some rendering in WPF so that I found the hints in MSDN which suggest to use the light-weight DrawingVisual to make a rendering object (e.g. Triangle)
Whenever a property (e.g. color, coordinates) of the rendering is changed, it will render again.
(e.g. RenderOpen(); drawingContext.Draw(.......) ........)
Then I replace the rendering object with UIElement instead of DrawingVisual for the base class with other the same.
And I found that I only render one time no matter how I change the property. Still, I call InvalidateVisual() whenever a property is changed.
Eventually, I found that the rendering performance is much better than DrawingVisual.
Is it the truth?
Related
I've been trying to create a method to change the opacity of an object when I select it in a combo box so that I can see another object behind it. This is done prior to changing the camera position/direction to follow the 2nd object from the 1st object's position. This is done by cloning the object's default material with
this.DefaultMaterial = this.DefaultMaterial.Clone();
and then calling the
MaterialHelper.ChangeOpacity(DefaultMaterial,0.1);
method as I've written it out there.
The opacity seems to work properly for the most part, but for some of the objects in the view port, I can't see them through my initial opaque object. For instance, when I turn the camera to the particular object in question (the buggy one), instead of being able to see it behind my initial object I see through my initial object and past the second one(the buggy one) as if the buggy one wasn't even there. I just see what's behind it.
I have no idea why this is happening.
Does anyone know what could be causing this? Or if maybe there is a different way of making something transparent rather than setting its Opacity?
I saw some people referencing a TRANSPARENCY property, but wasn't sure if that applies to a FileModelVisual3D object, which is what the initial object is.
The buggy object is a UIElement3D, the opaque one is a FileModelVisual3D, there are other objects of the Point3DCollection class which also have the bug, as the UIElement3D does.
Because of the RenderOrder and depth buffer. You have to move your transparent object to the end of the rendering. It's not a bug, it's how rendering works.
Or change to use Helix-toolkit sharpdx, and use transparent rendering pass.
In GDI you just use System.Drawing.Graphics to manually handle the rendering.
In WPF is DrawingContext the way to go?
https://msdn.microsoft.com/en-us/library/system.windows.media.drawingcontext(v=vs.110).aspx
You could indeed override the OnRender method of a UIElement to define your own rendering instructions but note that this is not an immediate mode rendering API like Windows Forms's OnPaint. In fact there is no such API available in WPF.
The drawing operations of the DrawingContext are not used directly when the OnRender method is invoked. They are instead processed by the rendering thread at a later stage.
So depending on what you are trying to do, overriding the OnRender method may not be your best choice after all. You may want to stick to the "WPF way" of creating composite UI elements.
A custom WPF Control overrides OnRender. The method generates and displays a Path from custom data. The data provider is bound using a Dependency Property. The Dependency Property registers for an event when data changed. This event in turn calls InvalidateVisual().
However, after the InvalidateVisual() the OnRender is not always called.
We use the Prism Framework and the Region functionallity. The Control in question is embedded in such a Region, which is activated and deactivated. However, the Control's property "IsVisible" is true whenever the region is active. But still, when calling InvalidateVisual() the OnRender method is not called...
What could prevent the OnRender method from being called?
I just had this problem, too.
Context
I've got a load of controls based on the DynamicDataDisplay graph components inside a VirtualizingStackPanel (inside a ListBox).
When there are more controls that are visible at once, but not enough for the VirtualizingStackPanel to start re-using them when you scroll then I see this issue with the D3 AxisControl class. For some reason it does a lot of work in it's OnRender method, which it tries to trigger by calling InvalidateVisual when something changes.
In the problem case the problem controls call InvalidateVisual but they never get a call to MeasureOverride, ArrangeOverride or OnRender. Interestingly, most of the controls still work, in one particular problem case I get the last 3 out of a set of 11 failing to work properly. Notably those 3 (and only those 3) receive a call to MeasureOverride immediately before the data binding update that triggers the call to InvalidateVisual.
My Fix
In the end I managed to fix it by adding a call to InvalidateMeasure alongside the call to InvalidateVisual.
It's a horrible solution, but it's not a performance critical part of our application, so I seem to be getting away with it.
If the size of your control is staying the same, you should not be using InvalidateMeasure() or InvalidateVisual() because they trigger an expensive re-layout.
WPF is a retained drawing system. OnRender() might be better called AccumulateDrawingObjects(), because it doesn't actually draw. It accumulates a set of drawing objects which WPF uses to draw your UI whenever it wants. The magic thing is, if you put a DrawingGroup into the DrawingContext during OnRender(), you can actually efficiently update it after OnRender, anytime you like.
See my answer here for more details..
https://stackoverflow.com/a/44426783/519568
I just had this problem, too.
I had a scrollbar for a control which only figured out during OnRender() how much space is really needed to display all content, which could be bigger than the available display space and therefor needed a scrollbar. It could happen that OnRender() called some methods which ultimately changed the value of the scrollbar which was supposed to start OnRender() with InvalidateVisual().
However, OnRender() did not get called again after InvalidateVisual(). I guess the reason is that InvalidateVisual() sets some flags which tells WPF that the control needs to get drawn again, but once OnRender() finishes, that flag gets reset. Here some pseudo code how I expect it to happen:
//someCode:
control.InvalidateVisual()
//code of InvalidateVisual()
control.RedrawFlag = true;
//WPF some time later:
if (control.RedrawFlag){
control.OnRender()
//OnRender code
//do some stuff
//decide control needs to be redrawn
//however, RedrawFlag is alreday true!
//next line is not changing anything
control.RedrawFlag = true;
//WPF finished executing control.OnRender
control.RedrawFlag = false;
}
I didn't further investigate if WPF really works this way, but it would explain why OnRender() does not get called a second time.
Instead of wasting even more time, I changed how to calculate the total width of the control content can be and put this code outside of OnRender().
I'm trying to achieve a custom transition animation with a shadereffect on an image.
I'm using a system i made for specifying easing Bézier functions graphicaly and i process all the spline data in a class called Spline.
i'm animating a time property send to a Spline's static method to compute the Bézier data for easing.
then i get the computed value that i send to the Time property of my shader effect
but i can't use beginAnimation on this transition because the class playing the animation is a non-UI one and already inheriting from an abstract class.
If i want to use beginAnimation, i have to make the abstract class inherit from dependencyObject to use a dependency property as parameter of BeginAnimation but i get this error
this.BeginAnimation(TimeProperty, anim);
'MyClass' doesn't contain a definition for BeginAnimation and no extension method BeginAnimation accepting a frist argument of type 'MyClass' could be found (are you missing a using directive or an assembly reference)
all this dependency/Animatable system doesn't fit my needs since i'm not working on the ui directly and i'm totally stuck now
Any idea?
(I used a dispatcherTimer to do the trick but when the animation finish, i can see the background color of my application during half a second and then my second image finally shows up but i don't want this behavior since it will be marketed...)
Use a KeyFrame Animation. You can add single Frames to it. As example you can hide something every 2nd keyframe.
I finally used a Storyboard to achieve this, using the Dependency object inheritance on my abstract class.
And even if it's not great to use the Sotryboard/dependencyProperty system on a non-UI object(in my opinion), it works.
I have a storyboard to animate a DependencyProperty named Time in MyClass from 0 to 1.
In the PropertyChangedCallback of Time, i compute my new time value depending on my custom spline easing function, and then affect it to the Progress property of my Shader.
thanks for concern anyway.
In our Silverlight 2 project we have created an attached property to perform on-the-fly translation to text properties of various user controls. To achieve this, we hook the Loaded event of the FrameworkElement when the property is set. When the event fires, we take the existing text property value and perform some simple string substitutions on it, before replacing the property value with the translated text. However, this results in the control being rendered with the untranslated text, then the text is quickly replaced with the translated version.
Is there an alternate event we can hook that would fire before the control is rendered?
I've changed my code so that it now performs the translation as soon as the setter for the attached property is called. There's no need to wait for the FrameworkElement to have finished loading, as I can change the Text property long before the element is rendered.
My initial thoughts on using the Loaded event were to reduce the startup time of the application by only translating the controls that were visible on the screen. As it turns out, I'm duplicating some of the work performed by the runtime, as the runtime won't call the property setter until it needs to anyway.
I'm not totally sure about this, but can you use the LayoutUpdated event. It will fire when the control is resized and such (you could take measures to ensure your code only executes once.)
I know it doesn't seem like the "right" event for this but unfortunately Silverlight kinda leaves you standing there holding it when it comes to events.