In my MouseDoubleClick i may run into a case where i would like to call all the controls in a list with MouseDoubleClick. However i cant call MouseDoubleClick, only add/remove events to the chain.
How do i call MouseDoubleClick/OnMouseDoubleClick?
ATM i workaround the problem since i know the objects MouseDoubleClick function and i pass in the parameters myself calling that specific function. How do i call the event in the case i do not know what function is set to the control MouseDoubleClick
There are a number of ways you can do this:
As you are doing, hard-code the calls directly. Not a very flexible approach.
Add your own internal method to call in the controls (e.g implement a special Interface), or an event that you raise to which all the other interested controls subscribe. This only works if you have the source code for all the controls, or make derived UserControls of your own, which could be a lot of work.
Post a WM_LBUTTONDBLCLICK message to the underlying window for every control in your list. This should work for any kind of control as long as they don't do anything too naughty in their handlers. Note that you may need to work out fake x,y coordinates within each control to trick it into thinking that the double click was inside its own bounds - double clicks outside control bounds could cause undefined behaviours. And of course, the location of the click within the control can be important (e.g. you can double click on individual items displayed within a list box control)
i workaround the problem since i know the objects MouseDoubleClick function and i pass in the parameters myself calling that specific function. How do i call the event in the case i do not know what function is set to the control MouseDoubleClick
Related
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().
In my WPF application, I am using the ViewModelLocator without IoC. I am calling the static ViewModelLocator.Cleanup() method provided by the MVVM-Light framework from my own button which is tied to a "close window command". This Command calls the static ViewModelLocator.Cleanup(), which calls an instance Cleanup() method on my MainWindowViewModel instance. The instance Cleanup() method then sets the property to which the MainWindow binds its DataContext, to null. The setter on the property raises a PropertyChanged event. Curiously, setting this property to null does not cause the window to close.
I am trying to understand why this is the case? If I set the MainWindow's DataContext to null, should that not be the same as Window.Close()? In my case, the Window and all of its elements remain on the screen. However, if I attempt further actions, I get null pointer exceptions, indicating the DataContext binding Property has indeed been set to null; this has also been confirmed in the debugger.
I have created a workaround by hooking the Application.Exit event and issuing a Window.Close() in the event handler in order to create my own "Close Window" button (ie, to create same functionality for my own Button / Command as clicking the X button in the upper right of a Window). Since calling a UI element (ie, the Window instance) from MVVM directly is not MVVM friendly, I used a ViewService to implement the Window.Close() functionality in order to keep the workaround MVVM friendly. I am a big fan of the ViewService idiom (or pattern), but I just don't think it should be necessary here; except, I could see how exiting the app is a special case that perhaps should tie-in with the application lifecycle, and .Net seems to only allow exiting a WPF app by issuing the Window.Close() method.
Thoughts appreciated.
I believe I have found the answer to my original question, in addition to the one raised in my comments discussion with flq.
First, the answer to the original question is that the proper way to close the Window is along the lines of what I did in my described "workaround". Closing an app is a View-initiated process, as it is the Window control that has the bits for how to do it. You can of course hook the Application.Exit event so that you can perform cleanup on your ViewModels, prompt the user to save data, etc..
The question raised by me after some interesting discussion with flq is, if I don't just set a control's DataContext (ie, ViewModel) to null in order to release the View and ViewModel resources, how should I do it?
An interesting discussion with some nuances can be found here, but the basic answer is that you find the parent control and remove the control you want to close from its Children list. Note, this is a different technique with a different goal than just making the control not visible by setting is Visibility property to Collapsed. In the following example, "this" is the control to be removed (ie, "Closed"):
Panel p = (Panel) this.Parent;
p.Children.Remove(this);
I am not sure if you still need to then set the child (ie, "this") to null to re-claim its resources, or, if just removing it from the visual tree will cause WPF to re-claim the resources; the above linked discussion makes no mention. As mentioned in the original discussion, the above technique can be supplemented by hooking it to certain events, or using other application specific logic.
I am using a standard TreeView in a WinForms application and everything works fine except for one issue:
Parts of the system need to change depending on the selected TreeNode, which works fine using the AfterSelect event.
However, sometimes the TreeView will get cleared completely resulting in an empty selection which does not trigger this event.
At the momemnt I am calling the event callback manually to fix this issue.
This is obviously dangerous, since I will forget to call this function somewhere. Is there a "correct" way to do this?
Thank You!
This is by design. The underlying native Windows controls only generate notifications for things you cannot figure out yourself. The ListBox control for example doesn't have any event that tells you an item got added or removed. Which is because there is no way for the user to add or remove items. Similarly, there's no way for the user to remove the nodes from a tree view.
These kinds of changes requires code that you write. Since it is your code, you cannot not know that these changes happened. If you want an event then you'll have to raise it yourself. Beware that this is harder than it looks, the TreeNodeCollection class doesn't reliably let you generate an event for programmatic changes to the node collection. It doesn't behave like an ObservableCollection. You are definitely better off by not needing this event.
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.
I hope this makes sense.
I have created several WPF User Controls. The lowest level item is 'PostItNote.xaml'. Next, I have a 'NotesGroup.xaml' file that has an ItemsControl bound to a List of PostItNotes. Above that, I have a 'ProgrammerControl.xaml' file. Each ProgrammerControl has a grid with four different NotesGroup user controls on it (and each NotesGroup contains 0-many PostItNotes.
Then, I have my main window. It also has an ItemsControl, bound to a list of Programmers.
So, you end up with a high level visual view of a list of programmers, each programmer has four groups of tickets, each group of tickets has many PostItNotes.
The trouble I'm having, is that I want to respond to a mouse click event in my mainWindow's code behind file.
I can add a MouseClick event into my PostItNote.xaml.vb file and that is getting called when the user clicks a PostItNote, and I can re-raise the event; but I can't seem to get the NotesGroup to listen for that event. I'm not sure if that's even the correct approach.
When the user clicks the PostItNote, I'm going to do a bunch of business-logic type stuff that the PostItNote control doesn't have a reference to/doesn't know about it.
Can anyone point me in the right direction?
You have a couple choices:
Use the PreviewXXX events which are fired during the "tunneling" phase of WPF event routing. The parent controls can always preview the events going down through them to children.
Use the more advanced approach to hooking up events leveraging the AddHandler method to which you can pass a parameter called "handledEventsToo" which basically means you want to know when the event happened "within" you even if some descendent element handled the event itself.
I am going to take a flyer here. You probably don't want to be handling the event that high up; not really anyway. You are catching the event at the lower levels, which is unavoidable. Consider invoking a routed command from the PostItNote click event handler.
The routed commands bubble up and tunnel down through the tree. You can have an architecture where a high-level handler can listen to a logical event (Opening a postit note perhaps?). The handler for this doesn't need to care where the command originates from. It might be from you clicking something, it might be from clicking on a toolbar button. Both are valid scenarios.
It sounds like you are creating some kind of custom UI, am I right? You want the application to respond to the users interactions. That is what the RoutedCommands are for.