[Solved] Scaling a background image to the Model?

I want to have a scalable background image on my Diagram in WPF (.Net 4.0) application. I followed this advice and made it a node:

I would like to auto-scale the loaded image to be the bounds of the model by default, but I can’t seem to find that value. Do I have to traverse my model’s Node coordinates and find the least values and the greatest values?

Also, is there a good example of scaling a node via a drag-handle? I haven’t done an extensive search yet, but if it’s at the tip of your tongue…!

I presume there’s a far easier way.

Thanks!
-Dan

The Diagram.Panel.DiagramBounds gives you the extent of the parts of the diagram, in model coordinates. So if you want to have the image (held by an unbound Node) be stretched to cover that area, you could do:

    
      
        
      
    
and then in code:
Node backnode = myDiagram.PartsModel.FindNodeByKey("myBackground");
Image img = backnode.VisualElement as Image;
Rect b = myDiagram.Panel.DiagramBounds;
backnode.Position = b.Location;
img.Width = b.Width;
img.Height = b.Height;

I don’t know how often you want to execute this code.
Perhaps if you want users resizing it manually just doing it once is sufficient.
If so, you can execute it in a Diagram.InitialLayoutCompleted event handler.

Setting the attached property go:Part.Resizable=“True” will make the node be manually resizable by the user.

Thanks for the quick reply. That worked well. I’m having a performance problem that I just can’t track down, however. If I load a default background node in my Diagram, everything is fine. If I then load a new image into the background, it makes my machine slow to a crawl. Granted, I have about 200 nodes, and I’m about a 5000x5000 area in my Diagram, but if I load the default image at 5000x5000, the performance is still fine.

I’m running the 1.3 beta of GoWPF.

Here’s the relevent information for my background node:

        <go:Node MouseLeftButtonDown="Background_MouseLeftButtonDown" Id="BackgroundImage">
            <Image x:Name ="ImageData" Source="C:\Users\Dan\Documents\GoWPF 1.3.1.4\Samples\GoWpfBasic\argentina-flag.Png"
                Width ="4000" Height="4000" go:Node.Location="0 0"
                go:Part.LayerName="Background"
                go:Part.LayoutId="None" go:Node.Avoidable="False"
                go:Part.Selectable="True"
             />
            <ContextMenuService.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Page Setup" Click="PageSetup"/>
                    <MenuItem Header="Float Background Image" Click="FloatBackground"/>
                    <MenuItem Header="Lock Background Image" Click="LockBackground"/>
                    <MenuItem Header="Change Background" Click="ChangeBackground"/>
                    <MenuItem Header="----------------------"/>
                    <MenuItem Header="Clear Background" Click="ClearBackground"/>
                </ContextMenu>
            </ContextMenuService.ContextMenu>
        </go:Node>
        <ContextMenuService.ContextMenu>
            <ContextMenu>
                <MenuItem Header="Change Background" Click="ChangeBackground"/>
            </ContextMenu>
        </ContextMenuService.ContextMenu>
    </go:Diagram>

And the code that loads the new image:

    private void ChangeBackground(object sender, RoutedEventArgs e)
    {
        Node backg = OasisDiagram.PartsModel.FindNodeByKey("BackgroundImage");
        //Image img = backg.VisualElement as Image;
        String filename = OpenDialog("Background.jpg", ".jpg", "Images (.jpg)|*.jpg|(.png)|*.png");
        
        if (filename != null && filename != "")
        {
            //Load the image file here
            BitmapImage bi = new BitmapImage();
            bi.BeginInit();
            //bi.DecodePixelHeight = 1024;
            //bi.DecodePixelWidth = 1024; 
            bi.CacheOption = BitmapCacheOption.OnDemand; 
            bi.UriSource = new Uri(filename);
            bi.EndInit();
            Rect b = OasisDiagram.Panel.DiagramBounds;
            (backg.Content as Image).Width = b.Width;
            (backg.Content as Image).Height = b.Height; ;
            (backg.Content as Image).Source = bi;
            bi = null;
        }
        backg.Selectable = false;
    }

It’s not just loading the new image, but doing ANYTHING to the background image causes the stalling - even setting myBackground.Selectable = false; causes it.

It appears that I’m spending most of my time in these functions:
Northwoods.GoXam.DiagramPanel.ArrangeOverride(valuetype System.Windows.Size)
NW.GX.DiagramPanel.#0q(class System.Collections.Generic.HashSet1<class Northdoows.GoXam.Part>, class System.Collections.Generic.HashSet1)

I’m not having this problem on my sandbox project, but I don’t have the same structures.

I’ve never used the BitmapImage.CacheOption property – if you use a different value than “OnDemand”, does it change the performance?

Same effect. It even happens without loading a new Image

    private void FloatBackground(object sender, RoutedEventArgs e)
    {
        Node backg = OasisDiagram.PartsModel.FindNodeByKey("BackgroundImage");
        backg.Selectable = true;
    }

That alone will set it off. I’ll try and make a small test project and see if I can reproduce the problem. It’s tough since it relies on Entity Framework, and the Actipro framework, but I need to make a better sandbox for developing anyway.

I just tried adding the XAML (minus the context menu on the node, but including the ChangeBackground context menu command in the background and your latest background event handler code) to a random sample app.

Everything worked correctly and I did not notice any performance problems.

Walter,

I have made some progress on my issue, and hope you can help me get to the root of the problem. It turns out that the image has nothing to do with my performance problem - it’s the ContextMenu.

What I know now: Whenever I activate the context menu (right click), my entire app slows to a crawl. When I profiled the application, I loaded my diagram, right-click context menu (app crawls). and then just made a selection box at random places throughout my diagram (click-select, click-select, etc…)

Questions:

Is there anything you can suggest I look at to find the root cause? Is there an alternative method you can suggest to get a ContextMenu functionality without using the ContextMenuService? Is there any more information I can provide you with?
(I realize that I'm have your diagram inside my control, inside all this Actipro stuff, inside my app, but I haven't been able to extract my diagram into a standalone test app to see if it's a conflict between my controls)

The profiler points to this as the Hot Path:<div =""="">




    <tr>
        <td>
          <t></t><t></t><table ="expansion"="" style="margin-left: NaNpx;" cellpadding="0" cellspacing="0">
            <t><tr>
              <td>ActiproSoftware.Windows.Controls.Docking.DockingWindowContainer.ArrangeOverride(valuetype System.Windows.Size)</td>
            </tr>
          </t></table>
        </td>
        <td>56.62</td>
        <td>0.00</td>
      </tr>
      <tr>
        <td>
          <t></t><t></t><table ="expansion"="" style="margin-left: NaNpx;" cellpadding="0" cellspacing="0">
            <t><tr>
              <td>System.Windows.Controls.Control.ArrangeOverride(valuetype System.Windows.Size)</td>
            </tr>
          </t></table>
        </td>
        <td>56.62</td>
        <td>0.21</td>
      </tr>
      <tr>
        <td>
          <t></t><t></t><table ="expansion"="" style="margin-left: NaNpx;" cellpadding="0" cellspacing="0">
            <t><tr>
              <td>Northwoods.GoXam.DiagramPanel.ArrangeOverride(valuetype System.Windows.Size)</td>
            </tr>
          </t></table>
        </td>
        <td>56.40</td>
        <td>0.00</td>
      </tr>
      <tr>
        <td>
          <t></t><t></t><table ="expansion"="" style="margin-left: NaNpx;" cellpadding="0" cellspacing="0">
            <t><tr>
              <td>Northwoods.GoXam.DiagramPanel.#0q()</td>
            </tr>
          </t></table>
        </td>
        <td>33.44</td>
        <td>0.00</td>
      </tr>
      <tr>
        <td>
          <t></t><t></t><table ="expansion"="" style="margin-left: NaNpx;" cellpadding="0" cellspacing="0">
            <t><tr>
              <td>System.Windows.UIElement.Arrange(valuetype System.Windows.Rect)</td>
            </tr>
          </t></table>
        </td>
        <td>22.84</td>
        <td>0.01</td>
      </tr>
    
  </t></table>

I’m running the 1.3 beta of GoWPF.

Here’s the relevant information for my background node:

        <go:Diagram 
            PartsModel="{Binding Path=SchematicModel}"
            x:Name="OasisDiagram"
            Grid.Row="0" 
            Grid.Column="0"
            Grid.ColumnSpan="5"
            Grid.RowSpan="4"
            Padding="10"
            InitialPanelSpot="Center"
            InitialDiagramBoundsSpot="Center"
            HorizontalContentAlignment="Stretch"
            VerticalContentAlignment="Stretch"
            AllowDrop="False" 
            AllowDragOut="False"
            BorderBrush="Blue" BorderThickness="1"
            NodeTemplateDictionary="{StaticResource NodeTemplates}"
            LinkTemplateDictionary="{StaticResource LinkTemplates}">
           <ContextMenuService.ContextMenu>
            <ContextMenu>
                <MenuItem Header="Change Background" Click="ChangeBackground"/>
            </ContextMenu>
        </ContextMenuService.ContextMenu>
    </go:Diagram>
Function Name Inclusive Samples % Exclusive Samples %

Thought:
Since I’m getting trapped in the DiagramPanel’s ArrangeOverride method, is there a suggested way to override the ArrangeOverride method?

Taking this as my cue:

I tried just overriding the myDiagram.Panel = new CustomDiagramPanel(), but that’s read-only. Do I need to create a custom Diagram that implements a custom DiagramPanel?

Thanks!
-Dan

If you try the context menus in the GoWpfBasic demo app, do you notice any problems?
I don’t.

So I would suspect that it’s a problem using the ActiproSoftware DockingWindowContainer.
Try modifying GoWpfBasic to use an ActiproSoftware DockingWindow about the context menu, if that’s what you are doing.

If you really want to customize the Diagram’s DiagramPanel, you’ll need to replace the Diagram’s ControlTemplate. The Virtualizing sample has an example of that.

I think I found a clue to the problem. I can get the error without a Go object causing it - it starts with this DLL being loaded (in my output window)

‘Oasis.Presentation.vshost.exe’ (Managed (v4.0.30319)): Loaded ‘C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Accessibility\v4.0_4.0.0.0__b03f5f7f11d50a3a\Accessibility.dll’

And then a bunch of threads finish…

The thread ‘’ (0x1c7c) has exited with code 0 (0x0).
The thread ‘’ (0x2de4) has exited with code 0 (0x0).
The thread ‘’ (0x2298) has exited with code 0 (0x0).
The thread ‘’ (0x21ac) has exited with code 0 (0x0).
The thread ‘’ (0x357c) has exited with code 0 (0x0).
The thread ‘’ (0x2fb4) has exited with code 0 (0x0).
The thread ‘’ (0x36a8) has exited with code 0 (0x0).
The thread ‘’ (0x2fbc) has exited with code 0 (0x0).
The thread ‘’ (0x35bc) has exited with code 0 (0x0).

And THEN, if I shrink my app to the toolbar, and then pull it up again, everything is back to normal. Certainly doesn’t sound like it’s your problem at all. I can’t find out anything about this DLL or what’s it’s used for. Any ideas or leads? My Google-Fu has failed me on this one!

(Thanks for the help, BTW!)
-Dan

I have solved the performance issue, and it’s neither a Northwoods NOR an ActiPro problem, but rather (of course) a Microsoft problem.

Microsoft’s Tablet features are apparently pretty well Borked in .Net 4.0, and exhibit this problem under a certain set of conditions (UIAutomation clients, of which Tablet features are one of them).

The solution is described here:

It’s because of my Wacom tablet. This is unfortunate, but I’ll deal. Apologies for (Microsoft) wasting your/our time!

-Dan

I’m glad you figured it out and posted here.

My apologies for not being able to help you.