document view model not found when docking to floating window

Docking/MDI for Avalonia Forum

Posted 2 months ago by kucint
Version: 25.2.1
Avatar

Hi,

docking tool- and document- windows works fine in all scenarions except one:
see video below:

--- well, I don't know how I am supposed to attach a mp4 video file here ---

Neither cannot paste any image :(

in this scenario, the view model is not found. what is a reason of it?

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="using:Ava.Actipro.BugDockedDocumentApp.ViewModels"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:actipro="http://schemas.actiprosoftware.com/avaloniaui"
        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
        x:Class="Ava.Actipro.BugDockedDocumentApp.Views.MainWindow"
        x:DataType="vm:MainWindowViewModel"
        Icon="/Assets/avalonia-logo.ico"
        Title="Ava.Actipro.BugDockedDocumentApp">

    <Design.DataContext>
        <!-- This only sets the DataContext for the previewer in an IDE,
             to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
        <vm:MainWindowViewModel/>
    </Design.DataContext>

  <Window.Resources>
    <ControlTheme x:Key="DocumentWindowTheme" x:DataType="vm:DocumentViewModel" TargetType="actipro:DocumentWindow" BasedOn="{StaticResource {x:Type actipro:DocumentWindow}}">

      <!-- DockingWindow (BaseType) -->
      <Setter Property="Description" Value="{Binding Description, Mode=TwoWay}" />
      <Setter Property="Icon" Value="{Binding Icon, Mode=TwoWay}" />
      <Setter Property="IsFloating" Value="{Binding IsFloating, Mode=TwoWay}" />
      <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
      <Setter Property="SerializationId" Value="{Binding SerializationId, Mode=TwoWay}" />
      <Setter Property="Title" Value="{Binding Title, Mode=TwoWay}" />
      <Setter Property="WindowGroupName" Value="{Binding WindowGroupName, Mode=TwoWay}" />
      <Setter Property="CanClose" Value="{Binding CanClose, Mode=TwoWay}" />
      <Setter Property="CanFloat" Value="{Binding CanFloat, Mode=TwoWay}" />

      <!-- IMPORTANT: These properties should be configured last so that other bindings are applied before the window opens -->
      <Setter Property="IsActive" Value="{Binding IsActive, Mode=TwoWay}" />
      <Setter Property="IsOpen" Value="{Binding IsOpen, Mode=TwoWay}" />

    </ControlTheme>
  </Window.Resources>

  <!-- NOTE: The implicit DataTemplates defined here should normally be placed in Application.Resources so that they will be found by floating windows -->
  <Window.DataTemplates>
    <DataTemplate DataType="{x:Type vm:DocumentAViewModel}">
      <TextBox Text="This is Document A" Margin="5"/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:DocumentBViewModel}">
      <TextBox Text="This is Document B" Margin="5"/>
    </DataTemplate>
  </Window.DataTemplates>

  <actipro:DockSite x:Name="MainDockSite"
                    DocumentItemsSource="{Binding Documents}"
                    DocumentItemContainerTheme="{StaticResource DocumentWindowTheme}">
    <actipro:SplitContainer Orientation="Horizontal">
      <!-- Left panel with Node Library -->

      <actipro:ToolWindowContainer MinWidth="112" MinHeight="0">
        <actipro:ToolWindow Title="Node Library" ContainerDockedSize="286, 300">
          <TextBox Text="Node Library" Margin="5"/>
        </actipro:ToolWindow>
      </actipro:ToolWindowContainer>

      <!-- Main Workspace and Bottom Panel -->
      <actipro:SplitContainer Orientation="Vertical">
        <!-- Main Workspace -->
        <actipro:Workspace>
          <actipro:TabbedMdiHost/>
        </actipro:Workspace>
        <!-- Bottom panel with Node Info and Log Viewer -->
        <actipro:ToolWindowContainer>
          <!--<actipro:ToolWindow Title="Node Info"/>-->
          <actipro:ToolWindow Title="Log Viewer">
            <TextBox Text="Log Viewer" Margin="5"/>
          </actipro:ToolWindow>
        </actipro:ToolWindowContainer>
      </actipro:SplitContainer>
    </actipro:SplitContainer>
  </actipro:DockSite>
</Window>

Suggestion:
maybe " <!-- NOTE: The implicit DataTemplates defined here should normally be placed in Application.Resources so that they will be found by floating windows -->" is the issue?

I tried to move the document templates to App, but it did not solve the problem.

I attach full source code of test app to easely repro the issue:


--- well, I don't know how I am supposed to attach a zip file here ---

Comments (6)

Posted 2 months ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hello,

If you need to send attachments, you can either link to an external sharing site or you can use our ticket system.  We'd prefer you send the sample project to our ticket system and then we can interact with you there.  Please make sure you exclude the bin/obj folders from the .zip you send so it doesn't get spam blocked, and include the video showing how to reproduce it.

To answer your question, yes, DataTemplates for this should be in the ApplicationResources since resources typically only look up to a top level Window.  Anything floating is in a separate Window.  Whereas resources in Application.Resources can be found app-wide.  However if that isn't the problem here, we can try and narrow it down with your sample once we receive it.


Actipro Software Support

Posted 2 months ago by kucint
Avatar

OK.
I've created a ticket (Ticket Number: 3AE-30A99A6B-0006) and attached a video and source code there.

As you will see, the view model is found correctly in both scenarios, when window is docked and when it is floating.

The only way to reproduce the issue is to make the document floating AND dock it centrally, as the video shows.
So, it is a bit strange that Templates can be found for floating document docked to (any) border, but cannot be found when document is docked centrally.

looking forward for your help.
best!
t.

Posted 2 months ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Thank you for submitting the sample.  There are couple of reasons why you are seeing what you're seeing.

Your sample is configured the same as the original post above which has the data templates defined on the MainWindow.axaml.  That works great for anything docked in the DockSite, but may fail when you float the items outside of that window.  I say "may fail" because Avalonia has a tendendency to cache templates, and I think that is driving confusion about what is happening.  The floating documents appear to be working fine (at least one of them anyway), but that's only because the data template is cached.  When you see the one document fail, it is because it is trying to requery the data template and cannot locate it.  If either document window were to have been opened in an initial floating state (never docked), I would expect neither document would show its template.

In order for floating windows to properly locate the data template, those data templates need to be defined in App resources.  I checked your sample, and you did have the data templates there at one point and commented them out.  If I comment out the data templates in MainWindow.axaml and uncomment the same ones in App.axaml, everything works as expected and the "Not Found" message goes away.

Your sample, as submitted, was configured with data templates in MainWindow.axaml and a custom IDataTemplate in App resources.  If this custom IDataTemplate is how you would prefer to configure your data templates, you should uncomment the data templates defined in MainWindow.axaml as those are being found before your custom IDataTemplate is located.  If you do that, you should notice that all the documents in your sample show the "Not Found" message even when docked.  That's because your implication (at least in the sample you provided) is incomplete.  The logic is attempting to find the "View" associated with a "ViewModel" just taking the type name and replacing "ViewModel" with "View".  So "DocumentAViewModel" is looking for "DocumentAView", but that view is not defined in your sample.

In summary... 

  1. Only configure the data templates in App.axaml, not in MainWindow.axaml
  2. Choose to either explicitly define the data templates (like in the sample) or use the custom IDataTemplate approach.
  3. If using the custom IDataTemplate, just make sure the logic is complete and each view model has a corresponding view.


Actipro Software Support

Posted 2 months ago by kucint
Avatar

Thank for clarification.
I was not aware of the fact that Avalonia caches templates.
I did neither know anything about the "View" associated with a "ViewModel" paradigm.

Still I am a bit confused....

I do not use the IDataTemplate in my code sample at all. Should I have it?

I understand that having templates in MainWindow.axaml is a bad idea.
I have to move them to App.axaml somehow, but I dont know how exactly, or - what is the prefered way to do it.

Posted 2 months ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Our samples were built to use a Data Templates Collection.  Avalonia Docs have some good information on how to use them if it is new to you.  To keep relevant code together in our samples, we define the data templates in the sample itself.  As noted, though, that will not work well with floating windows since they cannot resolve the templates defined on other windows.  To make them broadly resuable within the application, you'd want to define them as part of your application resources as additionally discussed in Avalonia Docs.

The custom IDataTemplate, like was in your sample, is for more advanced scenarios and can provide programmatic control over defining a template instead of using a Data Templates Collection.

For your sample, you should modify App.axaml to remove the custom ViewLocator data template and just define the individual data templates as part of Application.DataTemplates.

<!-- Remove this
<Application.DataTemplates>
  <local:ViewLocator/>
</Application.DataTemplates>
-->

<!-- Keep this -->
<Application.DataTemplates>
  <DataTemplate DataType="{x:Type vm:DocumentAViewModel}">
    <TextBox Text="This is Document A" Margin="5"/>
  </DataTemplate>
  <DataTemplate DataType="{x:Type vm:DocumentBViewModel}">
    <TextBox Text="This is Document B" Margin="5"/>
  </DataTemplate>
</Application.DataTemplates>

Additionally, make sure you remove the data templates from your MainWindow.axaml since you don't want duplicates.

As for a recommended approach, that can vary by user.  We tend to suggest you use the approach that you are most comfortable with, and the Data Template Collection approach is a good way to get started.  If you later find that it no longer meets your needs, it would not be difficult to move to a more programmatic solution.


Actipro Software Support

Posted 2 months ago by kucint
Avatar

Hi,

Oh,  I see. The ViewLocator is repsonsible for this behaviour.
Now, I guess, I have the whole picture.

I succeeded to fix my production App. All is fine.
You may consider the topic as closed.

Thanks!
tomasz

Add Comment

Please log in to a validated account to post comments.