I am working on essentially a drawing editor that allows you to define geometries based on key points on existing geometries. The user is then able to add some information about the thing they just added, such as name, expected size, etc. The API I am using to accomplish it is the awesome Reversible API, though I hope that the question extends beyond the API that I am using.
There are basically a couple questions that I am seeking a little clarity on:
1) If you are supporting Undo/Redo with an application that supports selection in a Master/Detail manner, should changing the state of a drawing object also cause it to be selected? The example being that an undo operation changed the name of an element, and that change would not be obvious unless the element was selected. Is there considered a standard behavior for something like this?
2) When dealing with certain types of incremental changes (Dragging box, or using a numeric spinner), it seems to be standard form for a set of changes to be grouped into a single user interaction (mouse swipe, or the act of releasing the spinner button), but when dealing with MVVM, I currently only know that the property has changed and not the source of the change. Is there a standard way for these types of interactions to propagate to the view model without completely disintegrating the pattern?
When in doubt the best approach is to take a look at typical behaviour of OS controls and other applications on the platform in order to be consistent with what users will be familiar with. In particular, consistency with the most commonly-used applications. If you examine how other apps approach a UI issue you can often learn a lot, especially about subtle cases you may not have considered in your own design.
1) Conventionally, undoing tends to select the changed item(s), both to highlight what changed and to move the user's input focus back to the last edit so that they can continue. This works particularly well for content like text because if you undo/redo something you typed, chances are you want to continue editing in the area of the text you've just undone/redone. The main choice for you to make with master/detail is whether to select the master object only, or to select the precise detail that changed.
2) Your undo manager can use some intelligence to conglomerate similar actions into a single undo step. For example, if the user types several characters in a row, it could notice that these actions are all alike and concatenate them into a single undo step. Just how it does this depends on how you are storing and processing the undo, but with a decent object oriented design this should be an easy option to add (i.e. ask undo records themselves if they can be conglomerated so you can easily add new types of undo record in future). Beware though that accumulating too many changes into one step can be intensely irritating, so you may find the lazier implementation of one action = 1 step actually achieves a better UX than trying to be too clever. I'd start with brute force and add conglomeration only if you find you end up with lots of repetitive undo sequences (like 100 single pixel-left movements instead of just one 100-pixel jump)
Related
I have a little visual system for generation FSM's where the user can draw a graph using boxes (states) and link them with lines (transitions). This, in the end, generates c# code when user presses the "Generate code" button that defines the FSM in runtime.
I want my users to be able to change things like graph name, transitions names, states names, delete nodes, delete transitions and a bit more after the first save, so, I need a way to handle refactoring.
I'm struggling trying to find a non intrusive way to accomplish this. Have tried to apply a modification of a do/redo algorithm I made some time ago but couldn't be able to get something nice.
Could anyone explain how to create such a system, making it as less intrussive with existent code as possible?
Cheers.
I would suggest keeping the state in your graph datastructure, and generating the C# code anew on changes to the FSM, this is a simple solution that will allow arbitrary modification of the FSM-datastructure without having to worry about applying said modifications to the generated code.
For implementing 'refactorings' of the base FSM-data structure, you could use something like a Command Pattern to encapsulate the refactorings and undo/redo operations.
I'd like to add a research functionality to a software I'm developing. The idea is to adding some kind of "indexed" research, so when the user types in a text-box another, gui-component show the filtered results. Ex:
User types: a
aaa
aba
aab
user types: aa
aa
aab
and so on.
Sure this thing has a name (as it is used almost everywhere), but I don't know it and so until now I couldn't find anything useful over the web. I don't need the exact code, just a link to some resources (tutorial etc). Ty.
EDIT: I'm not looking for an autocomplete functionality: If I type in the textbox I'd like to see all the filtered result in a (for example) listbox near the textbox.
What you are trying to do is known as autocomplete (or it's a variation of that, you are simply filtering a list on-the-fly), and is a very common feature.
It requires that you be able to look up against your data quickly, as you have to be able to update the list as the input is formed. Of course, input can come in the form of keystrokes, and some people are very fast typists.
If your list is contained in-memory and is rather small, then your best bet would probably to filter over the list for search criteria (I'll refer to what is typed in the box as this).
If your list is not contained in memory, then you'll need to index your data somehow. Generally, databases are NOT good for this sort of thing. Some have text-indexing (SQL Server does) and if that suits your needs, you query against that.
If you aren't using a database, then you might want to consider using Lucene.NET to index your content. If your content is small enough, I'd recommend using the RAMDirectory, otherwise, the standard FSDirectory (file-based) will do fine.
With Lucene, you'll want to use the Contrib.Shingles package (it might be included in the latest build, I'm not sure); this is an n-gram filter which tokenizes items by characters, so basically, you could search on the first few characters (the search criteria) and get results.
Regardless of the approach you take, you need to take into account the speed of the inputs that come in. If you perform lookups every time a key is pressed, you'll have a good deal of requests that never will be applied.
Generally, you might want to start searching after the search criteria extends beyond two characters. Additionally, keep track of the number of requests that were made; if you have a request that is coming back and new input has been submitted, cancel the old request and submit the new request, the values from the old request won't be used.
When it comes to the UI component, it's better that you let another component vendor handle this; WinForms has an autocomplete mechanism for the TextBox, Silverlight has an autocomplete in the Silverlight Toolkit, jQuery has an autocomplete mechanism for web pages. Use one of those and shuffle your data to your control using the guidelines above.
If you are talking about a WinForms TextBox, then you might look at the AutomCompleteMode and AutoCompleteCustomSource properties of the TextBox.
I have done some research already as to how I can achieve the title of this question. The app I am working on has been under development for a couple of years or so (slow progress though, you all know how it is in the real world). It is now a requirement for me to put in Undo/Redo multiple level functionality. It's a bit late to say "you should have thought about this before you started" ... well, we did think about it - and we did nothing about it and now here it is. From searching around SO (and external links) I can see that the two most common methods appear to be ...
Command Pattern
Memento Pattern
The command pattern looks like it would be a hell of a lot of work, I can only imagine it throwing up thousands of bugs in the process too so I don't really fancy that one.
The Memento pattern is actually a lot like what I had in my head for this. I was thinking if there was some way to quickly take a snapshot of the object model currently in memory, then I would be able to store it somewhere (maybe also in memory, maybe in a file). It seems like a great idea, the only problem I can see for this, is how it will integrate with what we have already written. You see the app as we have it draws images in a big panel (potentially hundreds) and then allows the user to manipulate them either via the UI or via a custom built properties grid. The entire app is linked up with a big observer pattern. The second anything changes, events are fired and everything that needs to update does. This is nice but I cant help thinking that if a user is entering text into a texfield on the properties grid there will be a bit of delay before the UI catches up (seems as everytime the user presses a key, a new snapshot will be added to the undo list). So my question to you is ....
Do you know of any good alternatives to the Memento pattern that might work.
Do you think the Memento pattern will fit in here or will it slow the app down too much.
If the Memento pattern is the way to go, what is the most efficient way to make a snapshot of the object model (i was thinking serialising it or something)
Should the snapshots be stored in memory or is it possible to put them into files?
If you have got this far, thankyou kindly for reading. Any input you have will be valuable and very much appreciated.
Well , Here is my thought on this problem.
1- You need multi level undo/redo functionality. so you need to store user actions performed which can be stored in a stack.
2- Your second problem how to identify what has been changed by a operation i think through Memento pattern , it is quite a challenge. Memento is all about toring initial object state in your memory.
either , you need to store what is changed by a operation so that you can use this information to undo the opertions.
Command pattern is designed for the Undo/Redo functionality and i would say that its late but its worth while to implement the design which is being used for several years and works for most of the applications.
If performance allows it you could serialize your domain before each action. A few hundred objects is not much if the objects aren't big themselves.
Since your object graph is probably non trivial (i.e. uses inheritance, cycles,...) the integrated XmlSerializer and JsonSerializers are out of question. Json.net supports these, but does some lossy conversions on some types (local DateTimes, numbers,...) so it's bad too.
I think the protobuf serializers need either some form of DTD(.proto file) or decoration of all properties with attributes mapping their name to a number, so it might not be optimal.
BinaryFormatter can serialize most stuff, you just need to decorate all classes with the [Serializable] attribute. But I haven't used it myself, so there might be pitfalls I'm not aware of. Perhaps related to Singletons or events.
The critical things for undo/redo are
knowing what state you need to save and restore
knowing when you need to save the state
Adding undo/redo after the fact is always a painful thing to do - (I know this comment is of no use to you now, but it's always best to design support into the application framework before you start, as it helps people use undo-friendly patterns throughout development).
Possibly the simplest approach will be a memento-based one:
Locate all the data that makes up your "document". Can you unify this data in some way so that it forms a coherent whole? Usually if you can serialise your document structure to a file, the logic you need is in the serialisation system, so that gives you a way in. The down side to using this directly is usually that you will usually have to serialise everything so your undo will be huge and slow. If possible, refactor code so that (a) there is a common serialisation interface used throughout the application (so any and every part of your data can be saved/restored using a generic call), and (b) every sub-system is encapsulated so that modifications to the data have to go through a common interface (rather than lots of people modifying member variables directly, they should all call an API provided by the object to request that it makes changes to itself) and (c) every sub-portion of the data keeps a "version number". Every time an alteration is made (through the interface in (b)) it should increment that version number. This approach means you can now scan your entire document and use the version numbers to find just the parts of it that have changed since you last looked, and then serialise the minimal amount to save and restore the changed state.
Provide a mechanism whereby a single undo step can be recorded. This means allowing multple systems to make changes to the data structure, and then when everything has been updated, triggering an undo recording. Working out when to do this may be tricky, but it can usually be accomplished by scanning your document for changes (see above) in your message loop, when your UI has finished processing each input event.
Beyond that, I'd advise going for a command based approach, because there are many benefits to it besides undo/redo.
You may find the Monitored Undo Framework to be useful. http://muf.codeplex.com/
It uses something similar to the memento pattern, by monitoring for changes as they happen and allows you to put delegates on the undo stack that will reverse / redo the change.
I considered an approach that would serialize / deserialize the document but was concerned about the overhead. Instead, I monitor for changes in the model (or view model) on a property by property bases. Then, as needed, I use the MUF library to "batch" related changes so that they undo / redo as a unit of change.
The fact that you have your UI setup to react to changes in the underlying model is good. It sounds like you could inject the undo / redo logic there and the changes would bubble up to the UI.
I don't think that you'd see much lag or performance degradation. I have a similar application, with a diagram that we render based on the data in the model. We've had good results with this so far.
You can find more info and documentation on the codeplex site at http://muf.codeplex.com/. The library is also available via NuGet, with support for .NET 3.5, 4.0, SL4 and WP7.
In informal conversations with our customer service department, they have expressed dissatisfaction with our web-based CSA (customer service application). In a callcenter, calls per hour are critical, and lots of time is wasted mousing around, clicking buttons, selecting values in dropdown lists, etc. What the dirrector of customer service has wistfully asked for is a return to the good old days of keyboard-driven applications with very little visual detail, just what's necessary to present data to the CSR and process the call.
I can't help but be reminded of the greenscreen apps we all used to use (and the more seasoned among us used to make). Not only would such an application be more productive, but healthier for the reps to use, as they must be risking injury doing data entry through a web app all day.
I'd like to keep the convenience of browser-based deployment and preserve our existing investment in the Microsoft stack, but how can I deliver this keyboard-driven ultra-simple greenscreen concept to the web?
Good answers will link to libraries, other web applications with a similar style, best practices for organizing and prioritizing keyboard shortcut data (not how to add them, but how to store and maintain the shortcuts and automatically resolve conflicts, etc.
EDIT: accepted answers will not be mini-lectures on how to do UI on the web. I do not want any links, buttons or anything to click on whatsoever.
EDIT2: this application has 500 users, spread out in call centers around North America. I cannot retrain them all to use the TAB key
I make web based CSR apps. What your manager is forgetting is now the application is MUCH more complex. We are asking more from our reps than we did 15 years ago. We collect more information and record more data than before.
Instead of a "greenscreen" application, you should focus on making the web application behave better. For example,dont have a dropdown for year when it can be a input field. Make sure the taborder is correct and sane, you can even put little numbers next to each field grouping to indicate tab order. Assign different screens/tabs to F keys and denote them on the screen.
You should be able to use your web app without a mouse at all with no loss of productivity if done correctly.
Leverage the use of AJAX so a round trip to the server doesn't change the focus of their cursor.
On a CSR app, you often have several defaults. you should assign each default a button and allow the csr to push 1 button to get the default they want. this will reduce the amount of clicking and mousing around.
Also very important You need to sit with the CSR's and watch them for a while to get a feel for how they use the app. if you haven't done this, you are probably overlooking simple changes that will greatly enhance their productivity.
body { background: #000; color: #0F0; }
More seriously, it's entirely possible to bind keyboard shortcuts to actions in a web app.
You might consider teaching your users to just use the Tab key - that's how I fill out most web forms. Tab to a select list and type out the first few letters of the option I'm attempting to select. If the page doesn't do goofy things with structure and tabindexes, I can usually fill out most web forms with just the keyboard.
As I had to use some of those apps over time, will give my feedback as a user, FWIW, and maybe it helps you to help your users :-) Sorry it's a bit long but the topic is rather close to my heart - as I had myself to prototype the "improved" interface for such a system (which, according to our calculations, saves very nontrivial amounts of money and avoids the user dissatisfaction) and then lead the team that implemented it.
There is one common issue that I noticed with quite a few of CRMs: there is 20+ fields on the screen, of which typically one uses 4-5 for performing of 90% of operations. But one needs to click through the unnecessary fields anyway.
I might be wrong with this assumption, of course (as in my case there was a wide variety of users with different functions using the system). But do try to sit down with the users and see how they are using the application and see if you can optimize something UI-wise - or, if really it's a matter of not knowing how to use "TAB" (and they really need to use each and every of those 20 fields each time) - you will be able to coach a few of them and check whether this is something sufficient for them - and then roll out the training for the entire organization. Ensure you have the intuitive hotkey support, and that if a list contains 2000 items, the users do not have to scroll it manually to find the right one, but rather can use FF's feature to select the item by typing the start of its text.
You might learn a lot by looking at the usage patterns of the application and then optimizing the UI accordingly. If you have multiple organizational functions that use the system - then the "ideal UI" for each of them might be different, so the question of which to implement, and if, becomes a business decision.
There are also some other little details that matter for the users - sometimes what you'd thought would be the main input field for them in reality is not - and they have an empty textarea eating up half of the screen, while they have to enter the really important data into a small text field somewhere in the corner. Or that in their screen resolution they need the horizontal scrolling (or, scrolling at all).
Again, sitting down with the users and observing should reveal this.
One more issue: "Too fast developer hardware" phenomenon: A lot of the web developers tend to use large displays with high resolution, showing the output of a very powerful PCs. When the result is shown on the CSR's laptop screen at 1024x768 of a year-old laptop, the layout looks quite different from what was anticipated, as well as the rendering performance. Tune, tune, tune.
And, finally - if your organization is geographically disperse, always test with the longest-latency/smallest bandwidth link equivalent. These issues are not seen when doing the testing locally, but add a lot of annoyance when using the system over the WAN. In short - try to use the worst-case scenario when doing any testing/development of your application - then this will become annoying to you and you will optimize its use - so then the users that are in better situation will jump in joy over the apps performance.
If you are in for the "green screen app" - then maybe for the power users provide a single long text input field where they could type all the information in the CLI-type fashion and just hit "submit" or the ENTER key (though this design decision is not something to be taken lightly as it is a lot of work). But everyone needs to realize that "green-screen" applications have a rather steep learning curve - this is another factor to consider from the business point of view, along with the attrition rate, etc. Ask the boss how long does the typical agent stay at the same place and how would the productivity be affected if they needed a 3-month term to come to full speed. :) There's a balance that is not decided by the programmers alone, nor by the management alone, but requires a joint effort.
And finally a side note in case you have "power users": you might want to take a look at conkeror as a browser - though fairly slow in itself, it looks quite flexible in what it can offer from the keyboard-only control perspective.
I can't agree with the others more when they say the first priority of the redesign should be going and talking to / observing your users and see where they have problems. I think you would see far more ROI if you find out the most common tasks and the most common errors your users make and streamline those within the bounds of your existing UI. I realize this isn't an easy thing to do, but if you can pull it off you'll have much happier users (since you've solved their workflow issues) and much happier bosses (since you saved the company money by not having to re-train all the users on a completely new UI).
After reading everyone else's answers and comments, I wanted to address a few other things:
EDIT: accepted answers will not be mini-lectures on how to do UI on the web. I do not want any links, buttons or anything to click on whatsoever.
I don't mean to be argumentative, but this sounds like you've already made up your mind without having thought of the implications on the users. I can immediately see a couple pitfalls with this approach:
A greenscreen-esque UI may not be
more productive for your users. For
example, what's the average age of
your users? Most people 25 and
younger have had little to no
exposure to these types of UIs.
Suddenly imposing this sort of
interface on them could cause a
major backlash from your users. As an example, look at what happened
when Facebook decided to change its
UI to the "stream" concept - huge
outrage from the users!
The web wasn't really designed with this sort of interface in mind. What I mean is that people are not used to having command-line-like interfaces when they visit a website. They expect visual medium (images, buttons, links, etc.) in addition to text. Changing too drastically from this could confuse your users.
Programming this type of interface will be tough. As in my last point, the web doesn't play well with command-line-like or text-only interfaces. Things like function keys, keyboard shortcuts (like ctrl- and alt-) are all poorly and inconsistently supported which means you'll have to come up with your own ways of accessing standard things like help (since F1 will map to the web browser's help, not your app's).
EDIT2: this application has 500 users, spread out in call centers around North America. I cannot retrain them all to use the TAB key
I think this argument is really just a strawman. If you are introducing a wholly new UI, you're going to have to train your users on it. Really, it should be assumed that any change to your UI will require training in one form or another. Something simple like adding tab-navigation to the UI is actually comparatively small in the training department. If you did this it would be very easy to send out a "handy new feature in the UI" email, or even better, have some sort of "tip of the day" (that users can toggle off, of course) which tells them about cool timesaving features like tab navigation.
I can't speak for the other posters here, but I did want to say that I hope you don't think we're being too argumentative here as that's not our (well OK, my) intent. Rather the reaction comes from us hearing the idea for your UI and not being convinced that it is necessarily the best thing for your users. You are fully welcome to say I'm wrong and that this is what your users will benefit most from; but before you do, just remember that at the end of the day it's your users who matter most and if they don't buy in to your new UI, no one will.
It's really more of a keyboard-centric mentality when developing. I use the keyboard for as much as possible and the apps I build tend to show that (so I can quickly go through my use cases).
Something as simple as getting the tab order correct could be all your app needs (I guess I'm not sure if you can set this in ASP.NET...). A lot of controls will auto-complete for the rest.
I have a main form at present it has a tab control and 3 data grids (DevExpress xtragrid's). Along with the normal buttons combo boxes... I would say 2/3 rds of the methods in the main form are related to customizing the grids or their relevant event handlers to handle data input. This is making the main forms code become larger and larger.
What is an ok sort of code length for a main form?
How should I move around the code if necesary? I am currently thinking about creating a user control for each grid and dumping it's methods in there.
I build a fair number of apps at my shop and try to avoid, as a general rule, to clog up main forms with a bunch of control-specific code. Rather, I'll encapsulate behaviors and state setup into some commonly reusable user controls and stick that stuff in the user controls' files instead.
I don't have a magic number I shoot for in the main form, instead I'll use the 'Why would I put this here?' test. If I can't come up with a good reason as to why I'm thinking of putting the code in the main form, I'll avoid it. Otherwise, as you've mentioned, the main form starts growing and it becomes a real pain to manage everything.
I like to put my glue code (event handler stuff, etc.) separate from the main form itself.
At a minimum, I'll utilize some regions to separate the code out into logically grouped chunks. Granted, many folks hate the #region/#endregion constructs, but I've got the keystrokes pretty much all memorized so it isn't an issue for me. I like to use them simply because it organizes things nicely and collapses down well in VS.
In a nutshell, I don't put anything in the main form unless I convince myself it belongs there. There are a bunch of good patterns out there that, when employed, help to avoid the big heaping pile that otherwise tends to develop. I looked back at one file I had early on in my career and the darn thing was 10K lines long... absolutely ridiculous!
Anyway, that is my two cents.
Have a good one!
As with any class, having more than about 150 lines is a sign that something has gone horribly wrong. The same OO principles apply to classes relating to UI as everywhere else in your application.
The class should have a single responsibility.
A number is hard to come up with. In general, I agree with the previous two posters, it's all about responsibilities.
Ask yourself, what does the code to customize behavior for grid 1 have to do with grid 2?
What is the responsibility of the main form? Recently I have been subscribing to MVP design patterns (MVC is fine as well). In this pattern, you main form is the presenter, or ui layer. It's responsibility should be to present data and accept user input.
Without seeing your code, I can only guesstimate as to what is the best course of action. But I agree with your feelings that each grid and it's customization code should live in a different control. Perhaps the responsibility of the main form should be to merely pass the data to the correct control and pass requests from the control back to the controller/presenter. It is the responsibility of each control to understand the data passed to it, and display it accordingly.
Attached is an example MVP implementation.
http://www.c-sharpcorner.com/UploadFile/rmcochran/PassiveView01262008091652AM/PassiveView.aspx