I have implemented a custom Undo/Redo stack and Im trying to get it to work with the WPF TextBox.
I have turned off the built in Undo-mechanism and hooked up my custom Undo on Ctrl+Z. Everything works fine accept that the caret in the TextBox is always being moved to index 0 on every undo/redo. The question is how to solve this?
I have tried having a custom behaviour on the TextBox which listens to TextChanged and is localizing the last change in the text-string. But this only works unless you start typing the same letter several times in a row. The my method breaks down.
What I ideally want is some kind of behaviour that only makes actual changes to the TextBox.Text-property. As it is now it is updated completely for every Undo, even if its only the last entered letter that is removed. This is of course no suprise since it listens to the Text-property on my PresentationModel which is triggering PropertyChanged on Undo.
But wouldnt it be great if there was some more fine-detailed way of telling exactly what had changed with the property-value, that only one or a couple of letters where inserted/removed in the string value. Then the TextBox could change only that without having to refresh its entire Text-value. Is there any such way of telling the TextBox this allready or could it be possible to make a custom TextBox that behaved in this way? Then it would be possible to pinpoint the exact location for the new caret without having it go straight back to 0 for every propertychange-update!
Related
I have a TreeView which holds approximately 100,000 TreeNodes or even more, I have optimized everything related to loading or unloading them on deserialization process but now I'm stuck with an issue I can't overcome.
Its important to mention I decided not to use the LabelEdit default event given by the control since its pretty tricky to make it work as I wanted to, Its widely known that there are a lot of "problems" with this particular event which have pushed many devs to implement their own custom TreeViews.
In my case I am using a ContextMenu which has a Rename option, this brings a textbox right in front of the TreeNode and then I just simply change the TreeNode.Text property to whatever the user input was in the TextBox keydown event, once we trigger this event, the whole GUI freezes for a couple of seconds (4-5), I'm not doing any Depth search over the TreeNodeCollection or anything, I am directly accessing the TreeNode and modifying the property...
So, any thoughts on what could be wrong here? I already tried BeginUpdate / SuspendLayout / or even a custom solution found here How do I suspend painting for a control and its children? and nothing seems to help.
The first thing that comes to mind is that when the text is changed on the node, it must be redrawing the entire treeview.
In this situation, suspendlayout will not help, as the control isn't laying its contents.
I think beginupdate stops the drawing when nodes are being added to the list, but the text changed might bypass this.
Have you considered not using the keydown, and just updating the text once the user has dismissed the textbox? (i.e. done editing). Not ideal, but will limit the performance hit to once, instead of every key stroke?
I'm trying to make my own custom text editor for my program, which so far does syntax highlighting. It can't even edit text yet.
I've run into a snag when trying to display my caret.
In my OnRender() method, I use IsKeyboardFocused to check to see if I have keyboard focus, which if I do, then it goes ahead and draws my cursor.
I have told the keyboard via Keyboard.Focus(MyCustomTextEditor) to focus on my control when I click on it with my mouse, and when I intercept it using a GotKeyboardFocus event handler, I can verify using debugging messages that the focus was passed successfully.
However, no matter what I do, I can't seem to make IsKeyboardFocused = True inside OnRender(). I placed Debug.Print()'s at the beginning, end, middle, and every other place imaginable inside OnRender(), with the results always being False.
My method seems pretty straightforward. I just don't understand what I could have left out. Thanks for your time reading this!
Have you tried using FocusManager.FocusedElement to figure out what element is focused when you're expecting your control to have focus? That should give a few clues.
Shot in the dark, is OnRender() being called again after control load, or are you only checking on init? I recall focus issues involving setting focus on a control during the Loaded event, only to have focus revert afterwards.
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.
I have a following requirement for a very complex UI. (Complex here means there are lot of controls in the form [approximately 100]). I am using MVVM (if my problem requires it to slightly go away from MVVM I am ok with it)
My question is for Editable ComboBox and TextBox. But I would say I like to hear a common algorithm which will fit all controls.
Requirement 1 : The user edits the content and goes to next control, the color of the control/text should become red.
Requirement 2 : When the user comes back to the previously edited control and enters the value which was initially present, the color of the control/text should become back to black.
I know the requirement is tough and I have been breaking my head to design a generic algorithm using which I can store the previous value and call a function to change the color of control.
To just give you all an idea, --> I tried storing 2 properties for every TextBox like Default_Text and Text. But since the number of properties are huge, the memory footprint is very huge. Also maintaining so many properties is very tough.
--> I tried adding a Dictionary to every ViewModel to store what values have got changed. But here the problem I faced was giving unique keys to all the controls in my application, which is not very helpful
--> I had even thought and tried about subclassing controls like TextBox, ComboBox and overriding some methods to suit my requirement, but sadly I failed miserabley when I started adding validations and all.
So here I am stuck with designing a generic WPF property system/algorithm to handle all undo redo functionality, changing styles of controls,etc!!!
It will be really great if you experts can guide me in right direction and also help me in developing such an algorithm/system. A sample illustration will be nice though!!!
I found an answer to the above problem. I used attached behavior for this. More details on this link Function call from XAML from StackOverFlow.
When I databind, I store the initial value of the DataBound variable in the Tag property by using Binding=OneWay. Then I have written a attached behaviour for LostFocus event. Whenever the user enters a control and then goes to other control, it fires LostFocus event and calls my attached behaviour. In this, I check whether the value is equal to the value in Tag. If it is same, I display in black else I display in red.
Attached Behaviour rocks in WPF. I can achieve anything from that cleanly without code cluttering!!!!
Another alternative is to use some "dirty" tracking in your models (or viewmodels) and bind to a properties isdirty (and convert it to a color).
Suppose I have a Window with TextBoxes I want to use the values. Right now I'm thinking of either:
1) Updating each associated value once the cursor is out of focus, and once the user presses Ok I start the program
2) Once the user presses Ok, I retrieve all the values at once then start the program
I'm not sure which one is better though. First alternative seems more modular, but there's more semantic coupling since I each new box is supposed to be updating its respective value.
I realize this isn't all that important, but I'm trying to understand when to centralize and when not to. Other better approachers are appreciated too.
Use data binding to bind the text boxes' contents to objects in your code behind. WPF will take care of updating your attributes. Usually updating the data-bound value is done when the focus is lost on text boxes. However, you can also specify that it will happen whenever the value changes.