Dirkster99 / AvalonDock

Our own development branch of the well known WPF document docking library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Layout "locking" method for Anchorables (tool windows)

h0st1le opened this issue · comments

Does the library currently have a method of "locking" a layout. Ie. preventing the user from moving/docking/floating an anchorable or document?

I noticed a "CanMove" property for LayoutDocuments, but see no matching property for LayoutAnchorables. Additionally, it doesn't appear to be listed on the wiki documentation. What is the purpose of this property? Would this be a good place to start implementing such functionality?

Happy to contribute, but a suggestion up on where to start would be helpful.

I have added the missing Docu:
https://github.com/Dirkster99/AvalonDock/wiki/LayoutDocument#Properties

with a sample using the LayoutInitializer class (I can see no other way for setting this property please let me know if you see another way to set or bind this property and I will add this to the documentation):
https://github.com/Dirkster99/AvalonDock/wiki/CanMove-Property

You can costumize the LayoutInitializer in MLibTest with the above code snippet and you should be able to see that every document with this property set cannot be dragged away from its current position.

You should also set CanFloat=false and CanClose=false in the same manner to make sure that the document position cannot be changed by the user.

For the second part of your question about extending this for LayoutAnchoreables not being MoveAble we would have to edit the OnMouseLeftButtonDown overrides in:

(similar to LayoutDocumentTabItem.OnMouseLeftButtonDown(...))

since this is the code that gets executed when the user starts dragging a LayoutAnchorable.

What I am not sure about is the right place for the CanMove property for a LayoutAnchorable. I would prefer a class that keeps both CanMove properties (for Document and LayoutAnchorable) as a seperate setting to support maximum flexebility. So, I am thinking that extending the LayoutAnchorable class with that property is probably the best way to go.

Obviously, there should be other extensions like reading and writing the new property when serializing the layout (extend ReadXml and WriteXml). Would this be enough to get you started?

Hi Justin,

I have added the CanMove property for a LayoutAnchoreable which should enable locking the complete drag & drop behavior of the docking environment. For testing this:

  1. Make sure you start with a fresh layout (there should not be an old layout file on disc - for MLibTest remove the AvalonDock.Layout.config file from the bin folder)

  2. Insert the locking statements into the LayoutInitializer methods:

class LayoutInitializer : ILayoutUpdateStrategy
{
  public bool BeforeInsertAnchorable(LayoutRoot layout,
                                     LayoutAnchorable anchorableToShow,
                                     ILayoutContainer destinationContainer)
  {
    // Lock tool windows in their default layout position
    anchorableToShow.CanMove = false;
    anchorableToShow.CanHide = false;
    anchorableToShow.CanFloat = false;
    anchorableToShow.CanAutoHide = false;

    return false;
  }

  public void AfterInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableShown)
  {
  }

  public bool BeforeInsertDocument(LayoutRoot layout, LayoutDocument documentToShow, ILayoutContainer destinationContainer)
  {
    // Lock documents in their default layout position
    documentToShow.CanMove = false;
    documentToShow.CanFloat = false;
    documentToShow.CanClose = false;

    return false;
  }

  public void AfterInsertDocument(LayoutRoot layout, LayoutDocument documentToShow)
  {
  }
}
  1. Start the test application (eg MLibTest)

Expectation
Tool Windows & Documents should not be editable (dragable, closeable) as far as their Layout Posiition is concerned.

Can you test this for me with the current master branch and let me know if this works for you?
Thanx Drk

Dirkster99, thanks so much for implementing this! I had planned to come back when I finally had some free time, but this is even better. I'll pull down master and give it a go this evening, thanks again.

Apologies for not getting back to you sooner regarding this.

As described, setting the properties in the LayoutInitializer works properly, as long as any previous layout is first removed. I was curious though, what do you think of the ability to bind the property via xaml as in the MVVMTestApp using the style selector?

<Style TargetType="{x:Type avalonDockControls:LayoutAnchorableItem}">  
   <Setter Property="CanMove" Value="{Binding Model.CanMove, Mode=TwoWay}" />  
</Style>

The 'CanFloat', 'CanFloat' and 'CanHide' properties all appear to be accessible here.

You right I've added the dependency property as suggested above in this commit.

This should also enable the usage of styles as suggested:

<Style TargetType="{x:Type avalonDockControls:LayoutAnchorableItem}">  
   <Setter Property="CanMove" Value="{Binding Model.CanMove, Mode=TwoWay}" />  
   <Setter Property="CanFloat" Value="{Binding Model.CanMove, Mode=TwoWay}" />  
   <Setter Property="CanHide" Value="{Binding Model.CanMove, Mode=TwoWay}" />  
</Style>

I've been missing this because I previously missed the role of LayoutItems in AvalonDock. Its a big complicated project and I was neither the previous maintainer not the original author :-( which makes it kind of difficult to undestand all corners of the system but I guess I am slowly getting it :-)

You can test this with the current master or wait for the next release.

Testing indicates this works perfectly but I've run into something related.

I have setup a command that "locks" all the anchorable panes when activated, setting the "CanMove" and "CanFloat" properties of each anchorable to false. If all anchorables are docked this lock works well. However, if a pane is floating, it can still be dragged onto any other anchorable and will dock the floating pane into the locked anchorable.

This is the expected behavior, but is it possible to disable docking for an anchorable? I can override the context menu "Dock" option easily enough, but unsure if it is possible to override the default behavior of the overlay window? LayoutUpdateStrategy doesn't appear to fire for for these events, are there any other potential extensible areas I should investigate? I know this really runs counter to the entire purpose of a docking manager, but curious if you have any ideas.

This project is so complicated, it's difficult to know where to even start. Thanks for taking this monster on, and much appreciation for all the changes already. :)

I don't think there is a CanDock option so far. I did not have this on the table because I thought (without verifying it) that you only want to keep thinks in the DockingManager without ever worring about FloatingWindows. Could you describe your use case in a step by step manner so I can better understand what you actually want to do?

I can have a look and see if I can implement a similar CanDock property as the properties with been looking at so far ...

At this point I'm just being nitpicky, but the general use case is something like the following:

I have a mapping application with a variety of docks associated with various aspects of the program.

https://imgur.com/a/N8DlmkU

The user can move the docks around and setup the layout of the application according to their preferences. Once they have things like they want they can click a "lock" (seen on the base of the status bar) the layout. This prevents them from accidently grabbing a dock and moving it unintentionally. This whole process works great. However if a user chooses to float one of the docks (such as placing query results, on another monitor), if they move the floating dock over the "locked" layout the option to dock the floating window pops up. Ideally when the layout is in a locked state the floated window would not be able to dock, only float over the rest of the interface.

Does that make sense?

Your description makes perfect sense. I'll be looking into a CanDock property to see what we can do about Achorables and Documents that will not act as a docking target....

We can dissable the dock part of the drag & drop (dock) interaction by not adding the corresponding OverlayWindowHost into the collection of _overlayWindowHost in DragService.GetOverlayWindowHosts().

The downside of this approach is that it is not easy/efficient to navigate the elements (LayoutAnchorables, LayoutDocuments) inside each host (DockingManager, LayoutAnchorableFloatingWindowControl, LayoutDocumentFloatingWindowControl) to determine if they contain an item that would allow a Dock operation or not.

Therefore, I've implemented the new CanDock dependency property within the LayoutPanel class. This means we have only one property to control whether a drop operation is allowed for all three hosts previously named. The property supports interaction via binding and is serialized/deserialized to recover from last state (its default value is true - even if the CanDock attribute is not present in Xml - to not break earlier implementations).

Untitled

Obviously, CanDock should not be used without CanMove since user can otherwise drag items away without being able to dock them back again :-(

Please check the Issue_136_CanDock branch to test this solution and let me know if you can find any bugs.