DesignSurface and Zoom - winforms

I am trying to implement Zoom feature on a DesignSurface, which uses .Net 2 based Designer time architecture.
I have two approaches to handle ZoomChanged event:
Unload the Design surface and reload with Zoomed content.
Identify the affected properties and set them to Zoomed values of properties.
Problem:
In approach 1, Unload and Reload is quite a task for run-time and would unload and reload lot of properties which would not be affected by zoom change.
In approach 2, The properties being changed would raise lot of PropertyChanged events and execute relative handlers, which would make response quite slow. If, I want to unsubscribe and resubscribe all the event handlers, I would not have any single place to do it as it spans over lot of dependent components.
Any one at rescue?

Related

Scheduling UI tasks for after the visual tree has settled down

In XAML-based apps, quite often I need to manipulate on-screen elements, resize or move stuff around. The situation arises usually for very custom UI controls.
The timing of stuff loading and data-binding etc. can give rise to irritating timing issues.
Traditionally, my colleagues and I have worked around these problems by 're-dispatching' work to the UI thread so it runs later, when dependent properties are in the 'final' states.
Is there a better way to do this? What strategies have you found that work?
The LayoutUpdated event can be very noisy, fine-grained, and deregistering requires forgoing a Lambda for a method and thus not being able to access enclosed variables from the outer logic - its a bit of a 'mare.
Edit
I'll give a tangible example. A custom control draws an outline around a face when doing facial recognition, so we're talking totally custom stuff here, nothing XAML does out the box.
The image needs to be scaled and sized and the paths and geometries scaled and sized so its all in alignment.
When programmatically changing the heights and widths of elements, the impact is not immediate, its only once the UI thread is relinquished back to the XAML framework does the rendering subsystems rearrange everything.
Thus, logic that depends upon the changed values needs to run after the framework has rearranged everything, and so this work needs scheduling to occur later on the UI thread, hence resorting to dispatching. It smells.
Many events and virtuals are called at times when requisite data is not yet available. Sometimes, work needs to be done upon data arrival (i.e. property change notification) which is does not typically trigger the XAML layout events. In this case, we resort to dispatcher hacks.
What about using the Loaded event?:
Loaded += LoadedHandler;
...
private void LoadedHandler(object sender, RoutedEventArgs e)
{
// Do something here when controls have loaded
}
I discovered that in WPF, this dependency property metadata argument exists to help with the problems I'm talking about.
FrameworkPropertyMetadataOptions.AffectsRender
The enum doesn't exist in Windows Store applications, presumably since its designers think the InvalidateArrange method is a suitable alternative.
Possibly, we should be a) invalidating the arrangement within our DP change handlers b) making these arrangements over multiple passes c) tolerating incorrect layout in-between passes.
Still, the using lambdas with the dispatcher is nice since variables used in calculations can be referenced from inside the closure.

How to indicate allowable drage & drop targets?

I'm considering a UI design (using WPF), but I'm not sure how to implement a critical feature: The user will be assigning needs to resources. There are some rules about what assignments can be made, such as compatibility and availability. I would like to display a list of resources, and a list of needs. The user can make an assignment by dragging a need and dropping it onto an resource.
What I would like to do is show the user what possible assignments can be made by highlighting all assignable resources for a given need. This should be done when dragging any given need.
(I'm comfortable performing the highlight using a property on the resource ViewModels and triggers in XAML, and performing the drag & drop action.)
I don't see any events that are generic to dragging starting or stopping; they are either relevant to the source element, or to elements that are actively being dragged over. How can I evaluate a method to evaluate compatibility on every resource item when a drag is started?
EDIT:
As I am thinking about this more, it might be better to perform the highlighting function upon selection of the item rather than the start of dragging. As the items will typically be in ListViews or TreeViews, dragging will also cause the item to become selected. Additionally, the user will not have to initiate and hold a drag while considering their choices. As the list of targets may be long, the user may need to scroll to find one they want, which is not practical while dragging.
I can easily listen for the SelectionChanged events to evaluate the potential drop targets.
In WPF the drag drop services are well defined along with indicating applicability of which are valid draggable and droppable visuals for the dragged data.
http://msdn.microsoft.com/en-us/library/ms742859.aspx
EDIT
As per your requirement you need to indicate \ highlight \ focus valid droppable targets when drag starts.
For this the droppable visuals must register themselves for the type of data that is getting dragged. All drop targets will thus be notified when such data that they have registered for is getting dragged i.e. in DragDrop.DoDragDrop(..., <dragged data>, ...) call.
Now this is tricky, but you could use Clipboard services to hold the dragged data. The registered target visuals will be notified by the same Clipboard service when such data is added to the clipboard. You could have a command CanExecute() that constantly executes on the drag - drop view and checks the clipboard data is of the registered data type. If so it will set some view model based boolean property that has been attached against all those valid drop targets to true, that will highlight them thru the attached behavior.
In the case of falling back (drag or drop lost), the clipboard must be cleared.
But ofcourse this is easy said than done.... but worth a try.
While I have updated the question with my plans to pursue another UI approach (highlight upon selection), I have still been pondering what I perceive as a shortcoming in the WPF Drag & Drop services.
Suddenly I realized that the start of dragging calls my code in order to get the data being dragged. I can do whatever I want there, including the triggering of any additional UI effects! With this, it seems a little silly to expect such functionality in the DragDrop class...

Silverlight Binding in Pivot Control

I have a design question : In a pivot view (three "pages"), I have a lot of bindings. Well, about 12 items in each pivot view (TextBox, Map...).
I realized that these binding were slowing a lot the load of my view. But the binding on the first "page" of my pivot is the only one that needs to be loaded. I can put a progress indicator and load in a thread or something my other data (in fact, the binded data will be set only after an HTTPWebRequest).
How can I tell that to my application ? Like "onLoadPageX: bind items"
Thanks a lot, I don't know if i'm clear
You should be able to add a RoutedEventHandler for the Loaded event of each PivotItem. This event is fired when a particular PivotItem page is loaded; there is also a corresponding Unloaded event for when the page unloads, in case you need to free any resources.
Your question is quite vague but there are lots of options around showing a loading state, defering binding and having lots of controls in a pivot:
If you need to do anything that may take time then do it off the UI thread.
If you're doing something which takes time then you should show an indication to the user that something is happening. This could be a message or animation, depending on the likley time period and the rest of the application.
If your content is highly dependent upon data loaded from the web, be sure to have appropriate timeouts on failing to load the data. Also have useful messages if there is no data connection available.
If your UI is highly dependent on details loaded externally you could look at adding the controls to the UI once you know what you need to display.
If the UI will always have the same controls but different content in them, you could consider data-binding to objects which have placeholder content which is updated when the relevant information is downloaded from the web service.
If you have lots of items in your pivot you should consider defereing the loading of individual items so that you don't load them before they are needed. Only load the data on the items next to the one displayed. This way they appear preloaded to the user but ease the impact on the system.

Drop outside the control

I'm improving standart WPF TabControl. I want to add undocking functionality to it:
user drags the page just outside the TabControl and this page undocks in the window.
I want two events in this control - PageDragStart (raises when the page dragged outside) and PageDragEnd (raises when the page dropped outside)
I've got no problem with the first event.
But the second... OnDrop doesn't call, because the item dropped outside the tabcontol container. How can I know that it was dropped?
P.S. I want a universal control (so, undocking functionality shouldn't be connected and hardcoded with the window tabcontrol is placed or something like this)
Why use DoDragDrop at all? As I was reading your description, using Mouse.Capture by itself seemed the obvious solution:
Handle OnMouseLeftButtonDown on the tab and start capture
Handle OnMouseMove on the tab and update the cursor based on hit testing
Handle OnMouseLeftButtonUp on the tab, and stop the capture and make the appropriate change
The reasons you might ever consider DoDragDrop over simple mouse capture are:
Integration with Windows' OLE drag and drop so you can drag and drop between applications and technologies
Modal nature of DoDragDrop call (which actually seems to be more of a disadvantage to me)
Automated hit testing of targets
Standardized "drop operation" API to allow unrelated applications to handle copy vs move, etc.
You apparently don't need the OLE integration or multi-application support and you want to customize the hit testing, so it seems that DoDragDrop has no advantages over directly handling the mouse capture.
I solved the problem - in rather brutal and unsafe way. But for it's gonna work as the temporary solution.
Well, when I'm raising PageDragStart event, I call Mouse.Capture(this, CaptureMode.SubTree);
When the page is dropped somewhere - DoDragDrop throws different exceptions (COMException, NullReference (I couldn't find which object is null) and some others I don't remember).
I catch exception and call PageDragEnd event (if the property IsPageDraggingOut set to true).
As far as you can see this solution is really dirty and bad. But it works.
So, any other ideas (or some ideas how to work with Mouse.Capture properly)?

WPF Routed Events Across Element Tree Branches

I am wondering what the correct mechanism to enable communication between controls in WPF is. My goal is to not use conventional events and have to manually wire them up. The default behavior of routed commands (tunneling, bubbling) seems to be along the right lines but I guess I'm missing something.
Routed events are a new infrastructure provided by WPF which allows events to tunnel down the visual tree to the target element, or bubble up to the root element. When an event is raised, it “travels” up or down the visual tree invoking handlers for that event on any element subscribed to that event it encounters en route. Note that this tree traversal does not cover the entire visual tree, only the ancestral element
That is from this WPF Article
Using the image in the article, I want "Immediate Element #1" to initiate (raise) an event and then have "Immediate Element #2" handle that event. I'd like to achieve this without having to put any code in the "Root Element".
Basically fire an event (save, status updated, selection changed, etc..) from any where in my app, then have it be handled somewhere else with out the 2 parties knowing anything about each other. Is this possible?
I dont believe data bainding is the answer. I'd like to use Routed Events / Commands as they were designed just across the entire tree, not just within the source control's branch. Maybe it can't be done using routed events / commands, and data binding is the answer. I just dont know...
Any ideas?
The best mechanism is to refactor and separate the data view from the data model.
Create a data model that provides DependencyProperty properties (rather than standard C# properties) for each data point, but does not provide a UI. The values in the data model can affect each other when modified.
You can then bind each WPF element to the appropriate DependencyProperty from the data model. Modify the value in one element and all other elements are updated to reflect any data model changes in the bound properties.
If you want to transfer data between elements, Binding is the way to go. There are many tutorials and books about this on the net.
If you want to effect Style changes, then you can use DataTriggers, which also use Bindings.
There is no way to send events in the traditional sense between unrelated controls without wiring it up in the common root.

Resources