[SOLVED] Cannot instantiate GraphicsDeviceControl because the type is declared as abstract.

Hello, I’m Kipik and this is my first time getting into Gamedev and Moogame.

I was trying to make a little engine using FNA and Monogame, but I got an error after trying to create an Editor class for a TileMap Editor.

“The designer must create an instance of type ‘TileMapEditor.GraphicsDeviceControl’ but it cannot because the type is declared as abstract.”

And this is the code in the editor.cs:
`using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TileMapEditor
{
public class Editor : GraphicsDeviceControl
{
protected override void Draw()
{
GraphicsDevice.Clear(Color.Blue);
}

    protected override void Initialize()
    {

    }
}

}`

Thanks.

Can you post the code creating an instance of the control? If it’s trying to invoke the constructor (Ex. GraphicsDeviceControl dev = new GraphicsDeviceControl()) then you will need to assign a derived class instead (GraphicsDeviceControl dev = new Editor()) or create a factory method that creates the appropriate class, since GraphicsDeviceControl is abstract and cannot be directly instantiated.

Hi, sorry for the delay.

This is the GraphicsDeviceControl code.
``#region File Description
//-----------------------------------------------------------------------------
// GraphicsDeviceControl.cs
//
// Microsoft XNA Community Game Platform
// Copyright © Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.Xna.Framework.Graphics;
using OpenTK;
#endregion

namespace TileMapEditor
{
// System.Drawing and the XNA Framework both define Color and Rectangle
// types. To avoid conflicts, we specify exactly which ones to use.
using Color = System.Drawing.Color;
using Rectangle = Microsoft.Xna.Framework.Rectangle;

/// <summary>
/// Custom control uses the XNA Framework GraphicsDevice to render onto
/// a Windows Form. Derived classes can override the Initialize and Draw
/// methods to add their own drawing code.
/// </summary>
abstract public class GraphicsDeviceControl : GLControl
{
    #region Fields


    // However many GraphicsDeviceControl instances you have, they all share
    // the same underlying GraphicsDevice, managed by this helper service.
    GraphicsDeviceService graphicsDeviceService;


    #endregion

    #region Properties


    /// <summary>
    /// Gets a GraphicsDevice that can be used to draw onto this control.
    /// </summary>
    public GraphicsDevice GraphicsDevice
    {
        get { return graphicsDeviceService.GraphicsDevice; }
    }


    /// <summary>
    /// Gets an IServiceProvider containing our IGraphicsDeviceService.
    /// This can be used with components such as the ContentManager,
    /// which use this service to look up the GraphicsDevice.
    /// </summary>
    public ServiceContainer Services
    {
        get { return services; }
    }

    ServiceContainer services = new ServiceContainer();


    #endregion

    #region Initialization


    /// <summary>
    /// Initializes the control.
    /// </summary>
    protected override void OnCreateControl()
    {
        // Don't initialize the graphics device if we are running in the designer.
        if (!DesignMode)
        {
            graphicsDeviceService = GraphicsDeviceService.AddRef(Handle,
                                                                 ClientSize.Width,
                                                                 ClientSize.Height);

            // Register the service, so components like ContentManager can find it.
            services.AddService<IGraphicsDeviceService>(graphicsDeviceService);

            // Give derived classes a chance to initialize themselves.
            Initialize();
        }

        base.OnCreateControl();
    }


    /// <summary>
    /// Disposes the control.
    /// </summary>
    protected override void Dispose(bool disposing)
    {
        if (graphicsDeviceService != null)
        {
            graphicsDeviceService.Release(disposing);
            graphicsDeviceService = null;
        }

        base.Dispose(disposing);
    }


    #endregion

    #region Paint


    /// <summary>
    /// Redraws the control in response to a WinForms paint message.
    /// </summary>
    protected override void OnPaint(PaintEventArgs e)
    {
        string beginDrawError = BeginDraw();

        if (string.IsNullOrEmpty(beginDrawError))
        {
            // Draw the control using the GraphicsDevice.
            Draw();
            EndDraw();
        }
        else
        {
            // If BeginDraw failed, show an error message using System.Drawing.
            PaintUsingSystemDrawing(e.Graphics, beginDrawError);
        }
    }


    /// <summary>
    /// Attempts to begin drawing the control. Returns an error message string
    /// if this was not possible, which can happen if the graphics device is
    /// lost, or if we are running inside the Form designer.
    /// </summary>
    string BeginDraw()
    {
        // If we have no graphics device, we must be running in the designer.
        if (graphicsDeviceService == null)
        {
            return Text + "\n\n" + GetType();
        }

        // Make sure the graphics device is big enough, and is not lost.
        string deviceResetError = HandleDeviceReset();

        if (!string.IsNullOrEmpty(deviceResetError))
        {
            return deviceResetError;
        }

        // Many GraphicsDeviceControl instances can be sharing the same
        // GraphicsDevice. The device backbuffer will be resized to fit the
        // largest of these controls. But what if we are currently drawing
        // a smaller control? To avoid unwanted stretching, we set the
        // viewport to only use the top left portion of the full backbuffer.
        Viewport viewport = new Viewport();

        GLControl control = GLControl.FromHandle(graphicsDeviceService.GraphicsDevice.PresentationParameters.DeviceWindowHandle) as GLControl;
        if (control != null)
        {
            control.Context.MakeCurrent(WindowInfo);
            graphicsDeviceService.GraphicsDevice.PresentationParameters.BackBufferHeight = ClientSize.Height;
            graphicsDeviceService.GraphicsDevice.PresentationParameters.BackBufferWidth = ClientSize.Width;
        }

        viewport.X = 0;
        viewport.Y = 0;

        viewport.Width = ClientSize.Width;
        viewport.Height = ClientSize.Height;

        viewport.MinDepth = 0;
        viewport.MaxDepth = 1;

        GraphicsDevice.Viewport = viewport;

        return null;
    }


    /// <summary>
    /// Ends drawing the control. This is called after derived classes
    /// have finished their Draw method, and is responsible for presenting
    /// the finished image onto the screen, using the appropriate WinForms
    /// control handle to make sure it shows up in the right place.
    /// </summary>
    void EndDraw()
    {
        try
        {
            SwapBuffers();
        }
        catch
        {
            // Present might throw if the device became lost while we were
            // drawing. The lost device will be handled by the next BeginDraw,
            // so we just swallow the exception.
        }
    }


    /// <summary>
    /// Helper used by BeginDraw. This checks the graphics device status,
    /// making sure it is big enough for drawing the current control, and
    /// that the device is not lost. Returns an error string if the device
    /// could not be reset.
    /// </summary>
    string HandleDeviceReset()
    {
        bool deviceNeedsReset = false;

        switch (GraphicsDevice.GraphicsDeviceStatus)
        {
            case GraphicsDeviceStatus.Lost:
                // If the graphics device is lost, we cannot use it at all.
                return "Graphics device lost";

            case GraphicsDeviceStatus.NotReset:
                // If device is in the not-reset state, we should try to reset it.
                deviceNeedsReset = true;
                break;

            default:
                // If the device state is ok, check whether it is big enough.
                PresentationParameters pp = GraphicsDevice.PresentationParameters;

                deviceNeedsReset = (ClientSize.Width > pp.BackBufferWidth) ||
                                   (ClientSize.Height > pp.BackBufferHeight);
                break;
        }

        // Do we need to reset the device?
        if (deviceNeedsReset)
        {
            try
            {
                graphicsDeviceService.ResetDevice(ClientSize.Width,
                                                  ClientSize.Height);
            }
            catch (Exception e)
            {
                return "Graphics device reset failed\n\n" + e;
            }
        }

        return null;
    }


    /// <summary>
    /// If we do not have a valid graphics device (for instance if the device
    /// is lost, or if we are running inside the Form designer), we must use
    /// regular System.Drawing method to display a status message.
    /// </summary>
    protected virtual void PaintUsingSystemDrawing(Graphics graphics, string text)
    {
        graphics.Clear(Color.CornflowerBlue);

        using (Brush brush = new SolidBrush(Color.Black))
        {
            using (StringFormat format = new StringFormat())
            {
                format.Alignment = StringAlignment.Center;
                format.LineAlignment = StringAlignment.Center;

                graphics.DrawString(text, Font, brush, ClientRectangle, format);
            }
        }
    }


    /// <summary>
    /// Ignores WinForms paint-background messages. The default implementation
    /// would clear the control to the current background color, causing
    /// flickering when our OnPaint implementation then immediately draws some
    /// other color over the top using the XNA Framework GraphicsDevice.
    /// </summary>
    protected override void OnPaintBackground(PaintEventArgs pevent)
    {
    }


    #endregion

    #region Abstract Methods


    /// <summary>
    /// Derived classes override this to initialize their drawing code.
    /// </summary>
    protected abstract void Initialize();


    /// <summary>
    /// Derived classes override this to draw themselves using the GraphicsDevice.
    /// </summary>
    protected abstract void Draw();


    #endregion
}

}

``

I got it from here since the tutorial I was following wasn’t working

if you’re trying to integrate monogame to winforms I’d suggest MonoGame.Forms: MonoGame.Forms - Create your Editor Environment!

Will try this. Thank you so much!

Now I get this error when running the project


It seems you are missing some references. They are in this folder:

You need a reference to:

  • MonoGame.Framework
  • SharpDX
  • SharpDX.Direct3D11
  • SharpDX.DXGI

Alternativly you could install from nuget using the nuget package manager from visual studio:

I added all those libraries and still get the error from my last screenshot.

Please try to download the repo and run the test project:

If it runs successfully, then the error is on your end. If not then feel free to upload your project somewhere so I can take a look.

This is the project, I’d like to run a MonoGame Form in the TileMap Editor.

Please try the test project first and reply back with the result; this could save a lot of time.

If the test project is not working, I will download and try your project.

Oh sorry, i forgot to say that your test project is actually working.

Okay, nice to hear.

I recommend to create such a test project for yourself and then copy over your own classes (like for the tile map) step by step. I’m pretty sure you would find the error in that way. It’s even possible that no error will occure at all and that your editor will just run.

Try that and feel free to come back here if something is still not working or unclear.

Hi thanks for the help and sorry for not responding but I wasn’t able to work on this until today.

I tried making a new project from scratch and using the MonoGame Forms and it was all good, so I decided to follow this tutorial in order to make my TileSet Editor https://www.youtube.com/watch?v=jWOjc-VwjvM and I think I got another library issue:

When executing this code in order to load a Texture2D in my Image class, which has this code:
` public void Initialize(ContentManager content)
{
this.content = new ContentManager(content.ServiceProvider, “Content”);
if (!string.IsNullOrEmpty(Path))
texture = content.Load(Path);

        if (SourceRect == Rectangle.Empty)
            SourceRect = texture.Bounds;
    } `

This happens:
Exception thrown: ‘SharpDX.SharpDXException’ in SharpDX.dll
An unhandled exception of type ‘SharpDX.SharpDXException’ occurred in SharpDX.dll
HRESULT: [0x80070057], Module: [General], ApiCode: [E_INVALIDARG/Invalid Arguments], Message: The parameter is incorrect.

In the line texture = content.Load<Texture2D>(Path);

At first i thought it was because the image was too big, but I tried using a smaller one and it didn’t work either.

Then I found this but I don’t have access to GraphicsProfile so I’m kinda lost right now.

Try using the integrated ContentManager: Editor.Content It is available in your class which inherits from MonoGameControl or InvalidationControl.

You have access to GraphicsProfile. You need to set it with the PropertyGrid from Visual Studio (design-time):

GraphicsProfile

This worked! Things are finally taking shape. Thank you sooooooooooo much mate.

1 Like

Awesome to hear! Glad I could help :slight_smile:

Okay different question now…

Do you know how could I implement a Camera into my Game? I followed many tutorials but there’s a problem: all of the examples and tutorials I’ve been following modify spriteBatch.Begin() in the main Game class passing the Camera.Transform as a parameter, but given the hierarchy I have in my project classes, there’s no way I can directly access that first spriteBatch.Begin() and pass my Camera.Transform.

This is the method I have on my game.cs

protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);

        spriteBatch.Begin();
        ScreenManager.Instance.Draw(spriteBatch);
        spriteBatch.End();

        base.Draw(gameTime);
    }

ScreenManager does this:

public void Draw(SpriteBatch spriteBatch)
{
currentScreen.Draw(spriteBatch);
if (IsTransitioning)
Image.Draw(spriteBatch);
}

And then I have the GameplayScreen class, which inherits from ScreenManager and actually manages the player, maps etc.

public class GameplayScreen : GameScreen
{
Player player;
Map map;

    public Camera camera;

    public override void LoadContent()
    {
        base.LoadContent();

        camera = new Camera();
        XmlManager<Player> playerLoader = new XmlManager<Player>();
        XmlManager<Map> mapLoader = new XmlManager<Map>();
        player = playerLoader.Load("Load/Gameplay/Player.xml");
        map = mapLoader.Load("Load/Gameplay/Maps/Map2.xml");
        player.LoadContent();
        map.LoadContent();
    }

    public override void UnloadContent()
    {
        base.UnloadContent();
        player.UnloadContent();
        map.UnloadContent();
    }

    public override void Update(GameTime gameTime)
    {
        base.Update(gameTime);
        player.Update(gameTime);
        map.Update(gameTime, ref player);
        camera.Follow(player);
    }

    public override void Draw(SpriteBatch spriteBatch)
    {
        base.Draw(spriteBatch);
        map.Draw(spriteBatch, "Underlay"); // The Underlay tiles are drawn first in screen.
        player.Draw(spriteBatch); // Then the player is drawn.
        map.Draw(spriteBatch, "Overlay"); // Finally, the tiles drawn over the player.
    }
}

Any ideas? :confused:

I would simply instatiate the camera class in the base game class so that you can easily set the Matrix in the spriteBatch overload.

When you then initialize other components, which should be able to manipulate the camera, then just give those components the reference of the camera instance per overload in the corresponding constructor.

If this doesn’t solve your problem then please open a new topic and describe your problem there. You should do this for every new question / problem you have, because it could be also relevant for other users and it becomes easier to find solutions for problems in that way.

Thank you :slight_smile: :thumbsup: