ILScene in WindowsFormsHost

2019-07-06 02:39发布

问题:

I am trying to host an ILPanel in a WindowsFormsHost Control in WPF. Here's my code:

XAML:

<Window x:Class="ILNumericsCharacteristicViewer.ILView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:forms="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
    Title="ILView"
    Width="300"
    Height="300"
    Loaded="ILView_OnLoaded">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="auto" />
    </Grid.RowDefinitions>

    <forms:WindowsFormsHost x:Name="WindowsFormsHost" Margin="5" />

    <Button x:Name="ButtonClose"
            Grid.Row="1"
            HorizontalAlignment="Right"
            Click="ButtonClose_OnClick"
            Content="Close" />
</Grid>

Code Behind:

public partial class ILView : Window
{
    private ILPanel ilPanel;

    public ILView()
    {
        InitializeComponent();
    }

    private void IlPanelOnLoad(object sender, EventArgs eventArgs)
    {
        ILArray<float> A = ILMath.tosingle(ILMath.rand(3, 10000));

        var scene = new ILScene {
    new ILPlotCube(twoDMode: false) {
        new ILPoints {
            Positions = A,
            Color = null,
            Colors = A,
            Size = 2,
                    }
                }
        };
        var pcsm = scene.First<ILPlotCube>().ScaleModes;
        pcsm.XAxisScale = AxisScale.Logarithmic;
        pcsm.YAxisScale = AxisScale.Logarithmic;
        pcsm.ZAxisScale = AxisScale.Logarithmic;

        ilPanel.Scene = scene;
    }

    private void ButtonClose_OnClick(object sender, RoutedEventArgs e)
    {
        Close();
    }

    private void ILView_OnLoaded(object sender, RoutedEventArgs e)
    {
        ilPanel = new ILPanel();
        ilPanel.Load += IlPanelOnLoad;
        WindowsFormsHost.Child = ilPanel;
    }
}

The line WindowsFormsHost.Child = ilPanel; throws an Argument Exception: "Parameter is not valid." Stack Trace:

at System.Drawing.Bitmap..ctor(Int32 width, Int32 height, PixelFormat format) at ILNumerics.Drawing.ILBackBuffer.set_Rectangle(Rectangle value) at ILNumerics.Drawing.ILGDIDriver.set_Size(Size value) at ILNumerics.Drawing.ILOGLControl.OnResize(EventArgs e) at System.Windows.Forms.Control.OnSizeChanged(EventArgs e) at System.Windows.Forms.Control.UpdateBounds(Int32 x, Int32 y, Int32 width, Int32 height, Int32 clientWidth, Int32 clientHeight) at System.Windows.Forms.Control.UpdateBounds() at System.Windows.Forms.Control.WmWindowPosChanged(Message& m) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

回答1:

If the rendering controls of ILNumerics are not loaded from a regular application, you will have to give a hint, in order to distinguish regular rendering from design time behavior. Frameworks, which load the library dynamically at runtime (VSTO, devenv, LinqPad and obviously MEF) may cause ILNumerics controls to 'think' to be used in a designer. Hence the design time replacement ('circle') you found.

In order to make ILNumerics render the 'runtime way' instead, add the following setting to your app.config:

key="ILNIsHosted" value="true"

In the context of the app.config settings file:

<configuration>
  <appSettings>
    <add key="ILNIsHosted" value="true"/>
  </appSettings>
</configuration>

The use of the app.config enables the application of the setting even in those scenarios, where the framework does not allow user code to be executed before the setup of any control. If your framework provides some initialization hook, you may just as well do the configuration by code:

ILNumerics.Settings.IsHosted = true; 

Keep in mind, that this code needs to be executed early in the application setup. At latest before ILPanel is initialized. Otherwise, the use of app.config is recommended.