WPF check if control is dragged - wpf

Is there a way to check, if the user is currently dragging a control in WPF? Events to handle start-drag and drop don't do the trick in my current application. Of course, a simple workaround could be implemented by just setting a bool-flag, which is set during start-drag, so a drag-n-drop can be seen as active.
Unfortunately, that solution is not very robust, since you have to manually reset that flag on drop - and have to think of all the possibilities, which could cause a drop-event to never occur (user presses ESC, not dropped into an allowDrop-control, ...).

I have a hacky sort of solution that I've come up with after spending lots of time trying to understand drag and drop in WPF.
The WPF InputManager which is "responsible for coordinating all of the input systems in WPF", does technically have a property that says whether or not a drag and drop operation is currently in progress.
/// <summary>
/// The InDragDrop property represents whether we are currently inside
/// a OLE DragDrop operation.
/// </summary>
internal bool InDragDrop
The above is from the official .NET Framework source code. Specifically InputManager.cs.
The problem is that, for some reason, it's declared as an internal property, so we can't access it... or at least we're not supposed to. internal and private members can still be accessed using refection. So InputManager.InDragDrop can technically be read by doing the following:
VB.NET
GetType(InputManager).GetProperty("InDragDrop", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance).GetValue(InputManager.Current)
C#:
typeof(InputManager).GetProperty("InDragDrop", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(InputManager.Current);
I have used this and it does work, but its not an officially supported feature of WPF so use at your own risk. There's technically a chance that Microsoft could change the way InputManager works in the future and remove or rename this property, thought personally I doubt it.

Related

WPF Numeric only TextBox - Handle it with event or command?

I am attempting to create a TextBox that only allows numeric characters and a decimal point. I don't need assistance in writing the code, but on the concept. I am using MVVM to design the WPF application and I'm not sure whether to use an event or event-to-command.
I have read several different viewpoints regarding this topic:
(I have found this to be a little extreme and as some have called it "counter-productive", but it upholds the "purity" of MVVM): Never have any code behind your View. To prevent this, use MVVM Light Library. In short, convert events to commands so that everything can be controlled in the ViewModel.
(The second argument does not uphold the (maybe over excessive) "purity" of MVVM): Not everything must be handled in the ViewModel and it is ok to create Events to handle certain UI requirements.
I was leaning more towards the second option because of simplicity and, as I have stated previously, the first option seems a little extreme. In my specific case (creating a numeric only TextBox) would most people prefer either of the above options or one I have not discovered?
You should handle this as an event in .cs file. You are trying to add functionality in a control. Like Text in a TextBox .They all are handeld in .cs file. ViewModel is resposible for holding the data and Behavior based on that Data for View not for the functionality of Control.
This should be handled directly in the View rather than involving the ViewModel, but there's no need to reinvent the wheel.
Depending on your exact numeric requirements, use a control such as DoubleUpDown or IntegerUpDown from the Extended WPF Toolkit (available via NUGet)

C# Winforms Custom control, binding on propertychange is not working and causing tabbing issues

I've just upgraded an old .NET 1.1 Winforms app that uses CSLA to .NET 4.0 and a later version of CSLA which supports the use of the INotifyPropertyChanged interface.
A large part of the reason for doing this is the databinding improves - e.g. being able to update on change when binding instead of when validating (tabbing off).
I have custom user control, NumberBox. Essentially it's just a textbox with a few properties such number type, decimal places etc.. I have exposed a public property of type object called BindableValue. It was this property that I was binding my CSLA classes (standard .NET classes inheriting validation rules, property changed and various stuff) integer property to, in this particular case it the class property is integer.
My problem having upgraded are the following:
If I enter a value, e.g. 1234, into my number box control it doesn't push the value back into the class' property it is bound to until I tab off, even though I have configured an object binding source to the custom BindableValue property with the update mode set to Property change.
Having entered value as in (1) if I go back and delete the value I am then prevented from tabbing off or clicking off the number box. I have set VS2010 to throw when .NET exception is thrown but it's not breaking.
It's been a while since I did WinForms stuff so I'm at a bit of a loss where to start. Any tips as well as a solution would be much appreciated.
EDIT:
I've tried a number of different things and am getting nowhere fast, it's getting really frustrating now:
I followed the info on MSDN, i.e. I added a ComplexBindingProperties attrib, slightly different in the textbox's private keyUp event handler I raise the event as indicated by the linked article OnBindableValueChanged(). However in all cases my event BindableValueChanged is always null.
I read similar articles to (1) but instead of declaring the event using EventHandler they used PropertyChangedEventHandler, tried this same result.
I added the DefaultBindingProperty attrib.
[You can read about this experience on my companies blog too - OCC Blog - Binding woes ]
I finally figured it out so thought I'd share it here to save someone else the tedium of trawling through Google reading lots of responses that say they work but in .NET 4.0 no longer seem to apply.
Okay, a lot of stuff I was reading on Google kept telling me my usercontrol had to have a Changed event using either EventHandler or PropertyChangedEventHandler delegates - different pages indicated different delegate. I tried both - fail!
What I had to do in .NET 4.0 is actually much nicer. Simply put just like my class that I was binding my usercontrol to does I had to implement the INotifyPropertyChanged interface. Then in my usercontrol when I wanted to pushback into my source object I just raised the PropertyChanged event (e.g. PropertyChanged("BindableValue"); ) the interface defined and hey presto all was well with the world again.
This above is a lot more elegant but unfortunately articles, forums and posts that are indexed by Google have not caught up with this yet for .NET 4.0 so all the existing stuff will lead you down dead ends and much frustration. I hope this saves someone else a lot of time.

Exiting an App or Closing a Control When Using MVVM

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.

does the wpf datagrid have a virtual mode like the winforms DataGridView?

The winforms DataGridView has a virtual model and uses the OnCellValueNeeded method to gets cell values from a a user defined data store.
How do i do this in wpf? The DataGrid doesn't seems to have a OnCellValueNeeded method.
Thanks
Not sure if this already helps you:
DataGrid uses UI virtualization, what means that objects are not created before they are visible on screen and the corresponding properties of your source objects will not be called as long as they are not visible. It means also that ui-elements are recycled after they are no more visible.
This is for free and you don't have to do additional coding to use this feature. If I interprete your question right, the main question is, how to know that a property of a business-object is needed. For UI-virtualization, this is when the property is called the first time - You can do some lazy initialization. But beware to put too heavy initialization code into the properties (DB synchronous lookups etc), otherwise your DataGrid will become very slow and unhandy.

How to get the count of undoable operation of a wpf richtextbox

how can i track the number of undo operation of a wpf richtextbox?
You can't do that. Undo logic is private inside TextBoxBase class and it depends on internal UndoManager class. I advise you not to hack with Reflection, because your code can break if MS decides to change implementation, but if you decide to do it anyway, you can use Reflector to get code of TextBoxBase.CanUndo property to understand how it works. Number of available undo operations is probably in the UndoManager.UndoCount property, but there's additional logic you need to consider.

Resources