WPF How to erase a DrawingVisual with RemoveVisualChild - wpf

Using WPF I'm drawing symbols in the "fast way" (Drawing rendered on DrawingVisuals, no Shapes). So... I can successfully draw them and get hit-tested with no problem.
But when trying to remove them, using RemoveVisualChild() plus RemoveLogicalChild(), there is no effect on the screen: No visual removing.
I'm implementing my own displaying canvas-alike object (overriding VisualChildrenCount, GetVisualChild, MeasureOverride and ArrangeOverride).
For a while I believed it was a problem of refresh, but after invoking many methods (InvalidateMeasure, InvalidateArrange, InvalidateViual and UpdateLayout, plus a Dispatcher calling technique for post background-threading execution) well... the supposedly erased objects are still there.
A curious thing is that new objects going to be drawn OVER these erased ones, are in fact rendered UNDER them!!
Any Ideas?

SOLVED: It was my mistake (what a shame!)... A recursive symbol update, started at property setter level, was repainting the object.

Related

Opacity bug in VS 2015 using Helix Toolkit

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.

WPF View leak - invisible, but still rendered in the background

There is a complex App, I try to simplify the scenario. There is a host .exe (.NET), which contains lots of controls (ActiveX, .NET, WPF).
One control is basically a grid with items (call it "list"), and when new selection happens, it sends a message to another WPF control (call it "DataView"). "DataView" will display details of the current selection of "list". When DataView receives that message, it will re-create it's ViewModel, and assign to its DataContext, so re-create its View.
Its View is very complex (XAML declared), full of controls, templates, and also contains several Images (type: NonDPIImage, derived from Image, with a few basic non-important change, just consider it as Image), and it's Source is a Converter, which creates the BitmapImages.
<Image.Source>
<MultiBinding Converter="{StaticResource ImageConverter}">
...
It works fine, but I noticed that after selection changes the "DataView" update is getting slower and slower.
I debugged, and found that after several selection changes, all previous Views are still in the memory, and all are rendering its content, so the ImageConverter is called for all previous Views, thus it's getting slower and slower.
I tried to profile, this is what I see after 10+ selection.
You see the previous Views are still in the memory (lower prio problem), with the Images, and those are still being rendered (high prio problem), making the App slower and slower.
I am not really familiar with WPF, I read after leaks (mostly not DependencyProperty is used or similar), but this control is so difficult that first I wand to quickly workaround, so prevent rendering the leaked Views, and later on investigate the memory issue. (of course both would be the best...)
I tried that before DataContext assigned to new value, set the current View Image.Source to null, so at least the leaked Image will not render itself, but that caused the new View(!) also to lose its Image.Source, looks like WPF is caching or sharing like some static data?
As my first prio is to stop the "invisible render", after this I tried to set some of the model properties to null before creating the new one (so it would still leak, but at least no render anymore), so when Converter will receive properties to create the image, will see it's null, and skip the render.
But it behaves very strange!
For the leaked instances the breakpoint is not hit in the properties_get code, like as WPF cached the values or so?
This prevented me this path to continue.
Any help / idea would be appreciated guys.
Can you post your ImageConverter code?
the thing is creating an image from code and serving it as source for Image object,
can create strong link between them and memory leaks in scenarios like yours.
Try looking here:
https://stackoverflow.com/a/21878235/7722174
I think I found the issue: there was a message hook added to the View HwndSource (AddHook()) , but was not removed. This kept the whole View (see the red rectangled class) alive.
Now if I call MyHwndSource.RemoveHook(WndProc) in the UserControl_Unloaded, the View will be also GCd.

Changing ListView.ShowItemToolTips raises ItemChecked events

Hi when I set ShowItemToolTips of a ListView with checkbox items to true in designer and change it to false in the code, the event ItemChecked is raised. The checked state itself is not changed though. But inside the (also raised) ItemCheck event the old value is not equal to the new value but the new value is the value that was previously visible. It seems like the items are re-inserted or reset in some way.
I tested this on two machines and projects. Why does this happen and how can I avoid it?
I'll explain the "why", a workaround is hard to come by. Some control properties are very impactful and can have odd side-effects when you change them. Like ShowItemToolTips, changing it after the ListView is created requires Winforms to completely destroy the native control and recreate it from scratch. Under the hood, it is a style flag (LVS_EX_INFOTIP) that's specified in the CreateWindowEx() call. The Control.RecreateHandle() method ensures it is effective. You'll see the flicker that this causes if you look closely.
So for a brief moment, the native control exists without yet being initialized with the original checkbox states. Getting a flaky event for that is a bug, but it is the kind that was either never fixed because doing so was too difficult or was just never discovered because nobody ever changes the ShowItemToolTips property after the control was created. It is very uncommon to do so.
In general, this native control re-creation trick has been a significant bug generator in Winforms. And workarounds are hard to come by, they fit either in the "deal with it" or the "don't do it" category. With the latter one strongly recommended in this case.

Access WPF DataGrid after making element visible

Currently I am stuck with a problem that is simple on the first sight. Its about automated GUI testing.
I want to make a row/cell of a WPF DatGrid completely visible by scrolling using ScrollIntoView(row) and then accessing the row/cell directly after. Unfortunately scrolling in ScrollViewer seems to happen asynchronously. This means I need to wait for the scrolling to finish before accessing the row/cell. For this purpose I found the ScrollChanged event I can subscribe.
There is only one detail I can not solve: If the row/cell I want to access is already visible (and no scrolling is necessary) I do not get that event and the algorithm gets stuck. I was not able to find a reliable way to predict if a call to ScrollIntoView(row) actually scrolls.
Any idea how to solve this?
To make sure layout is updated call UIElement.UpdateLayout after you ScrollIntoView and before you want to use item. Quoting MSDN it
Ensures that all visual child elements of this element are properly updated for layout.

MFC: how to render an Aero-style combo box for owner draw?

I have inherited a large MFC application which contains a CComboBox subclass that overrides OnPaint. Currently it does all its drawing by hand (with lines and rectangles), and renders a combo box that looks decidedly Windows 98-style. However, it otherwise works great and provides a lot of useful custom functionality that we rely on, and rewriting the entire control is probably not an option.
I would like to modernize it so that the OnPaint draws in Aero style where available (falling back to the old code when modern theming is unavailable). I've done this with some other custom controls we have, like buttons, and it works great for our purposes. I know there are some tiny behaviors that it won't get right, like gentle highlights on mouse-hover, but that's not a big deal for this app.
I have access to the CVisualStylesXP ckass, so I've already got the infrastructure to make calls like OpenThemeData, GetThemeColor or DrawThemeBackground pretty easily (via LoadLibrary so we don't force Vista as a min-system). Unfortunately, I don't know the proper sequence of calls to get a nice looking combo box with the theme-appropriate border and drop-down button.
Anyone know what to do here?
Honestly, I don't know why they originally tried to override OnPaint. Is there a good reason? I'm thinking that at least 99% of the time you are just going to want to override the drawing of the items in the ComboBox. For that, you can override DrawItem, MeasureItem, and CompareItem in a derived combo box to get the functionality you want. In that case, the OS will draw the non-user content specific to each OS correctly.
I think you best shot without diving in the depth of xp theming and various system metrics is take a look at this project: http://www.codeproject.com/Articles/2584/AdvComboBox-Version-2-1
Check the OnPaint of the CAdvComboBox class - there is a full implementation of the control repainting including xp theme related issues.
Not sure if it's the same situation - but when I faced this problem (in my case with subclassed CButtons), solving it only required changing the control declaration to a pointer and creating the control dynamically.
Let's assume that your subclassed control is called CComboBoxExt.
Where you had
CComboBoxExt m_cComboBoxExt;
You'll now have
CComboBoxExt* m_pcComboBoxExt;
And on the OnInitDialog of the window where the control is placed, you create it using
m_pcComboBoxExt = new CComboBoxExt();
m_pcComboBoxExt->Create(...)
Since this is now a pointer, don't forget to call DestroyWindow() and delete the pointer on termination.
This solved my particular problem - if your control is declared in the same way, consider giving it a try.

Resources