locked
Using Graphics, Canvas and WPF RRS feed

  • Question

  • Im working with some older legacy code that Im porting into a new WPF/MVVM application.  There (unfortunately) is a lot of custom drawing done in the legacy code using Panel and Graphics.

    Is there any way to use Canvas and preserve the old code?  An example of what the method calls are like:

    PaintEventHandler paint_event = paint_event = new PaintEventHandler(mt_Paint);

    private void mt_Paint(object sender, PaintEventArgs e)
    {
        Graphics refImage = e.Graphics;
        drawMap(refImage);
        // refresh container
    }

    I would love to be able to just use the drawMap method as it is, or very close anyways.

    Is this possible?  Examples, links?  Advice?

    Thanks!
    Monday, November 2, 2009 7:53 PM

Answers

  • If you want to use the old code as-is, you might want to consider hosting this inside of a WindowsFormsHost.  That would allow you to keep your existing, custom drawn code, as-is, and just place this inside of a control in your WPF application.

    Otherwise, if you truly need to port this to WPF, you'll need to rework the code.  WPF uses a very different paradigm for drawing than GDI (Panel/Graphics).  In GDI, you had to "manually" draw each time a redraw is requested.  WPF, on the other hand, uses retained mode graphics - you setup the primitives, and let WPF do the drawing itself.  This leads to needing to rework how the drawing occurs to port to WPF.  (Although, after the port, the code is usually MUCH simpler, since you're just doing one setup of the drawing).

    Reed Copsey, Jr. - http://reedcopsey.com
    • Proposed as answer by Geert van Horrik Monday, November 2, 2009 8:52 PM
    • Marked as answer by BryanCC Monday, November 2, 2009 10:19 PM
    Monday, November 2, 2009 8:10 PM

All replies

  • If you want to use the old code as-is, you might want to consider hosting this inside of a WindowsFormsHost.  That would allow you to keep your existing, custom drawn code, as-is, and just place this inside of a control in your WPF application.

    Otherwise, if you truly need to port this to WPF, you'll need to rework the code.  WPF uses a very different paradigm for drawing than GDI (Panel/Graphics).  In GDI, you had to "manually" draw each time a redraw is requested.  WPF, on the other hand, uses retained mode graphics - you setup the primitives, and let WPF do the drawing itself.  This leads to needing to rework how the drawing occurs to port to WPF.  (Although, after the port, the code is usually MUCH simpler, since you're just doing one setup of the drawing).

    Reed Copsey, Jr. - http://reedcopsey.com
    • Proposed as answer by Geert van Horrik Monday, November 2, 2009 8:52 PM
    • Marked as answer by BryanCC Monday, November 2, 2009 10:19 PM
    Monday, November 2, 2009 8:10 PM
  • Even though this seems to be the way to go for beginning (the drawing code is too complex and plentiful to refactor all now I think), the links and articles still leave me with some questions (of course :).

    For example, I want to use a Panel in WPF.  I see how I can do:
        <Grid>
            <WindowsFormsHost>
                <wf:Panel Name="coverageMapPanel" />
            </WindowsFormsHost>
        </Grid>


    But can I use the normal mvvm model?  So in the model I can retrieve the Panel (generated by analysis of data) and set the content?  Can I use binding?  I tried <wf:Panel Content=, or DataContext= but of course these are not valid for Panel. 

    At the end of the day I would like the user to select something, the correct panel is then pulled from an analysis package and then displayed in my WPF app.  Nothing I see shows how I can do this...?
    Monday, November 2, 2009 11:56 PM
  • If you're trying to do this with MVVM, there are a couple things I'd suggest.

    First, Windows Forms and MVVM don't really play nicely together - it's just a bit difficult to use.

    That being said, if you're trying to use multiple "panels" from within your ViewModel, you can setup a (WPF) UserControl per wf:Panel.  The UserControl would have the <Grid><WindowsFormsHost><wf:Panel...  </Grid> section.

    Then, you'd be able to setup a class to use as your UserControl's DataContext (a ViewModel for the UserControl, effectively, that provides the data).  It would have to not be too MVVM, since you'll probably need to use a lot of code to setup the Graphics correctly, but at least to your program, you'd just have a DataContext, and set the ViewModel, and the View can be created appropriately, etc.


    Reed Copsey, Jr. - http://reedcopsey.com
    Tuesday, November 3, 2009 12:08 AM
  • Hmm, not sure I understand.  So the legacy code I have generates a list of Panel objects, each with its own drawing stuff- how many Panels are in the list is determined by the user at runtime.  So for me to work with this, I was going to let my ViewModel take the selection criteria from other models, and then pull out the one Panel that corresponds with the selection and then hopefully apply that content to the xaml.  So even though there is only one Panel displayed, the content is updated.

    If I understand your suggestion, I would need to know up front how many panels to create- which unfortunately I dont know.

    I have, in fact lots of different types of panels that do a lot of drawing of different things.  All of which is analysis driven, so in the mvvm pattern, everything graphics would have to come from the viewmodel.  Some of these panels are pretty simple, and maybe could in fact be ported straight to wpf.  But some of them are godawful monstrosities that Im terrified to touch :) And these are the ones I was hoping to just update content on.

    Sadly I just dont know enough yet to identify the correct path forward- so many pros and cons to each side.

    Would what you suggest still work given my needs do you think?  Or maybe I have to just commit to porting everything to WPF?  Or something in between...?
    Tuesday, November 3, 2009 12:26 AM
  • Well, you may just need to somewhat hard-code this, given the mix of Windows Forms and WPF.

    What I was trying to suggest was to wrap the graphics into WPF user controls, so you can just treat them (and the code required to handle them) like a custom control - ie: it's an element of the View, so somewhat outside of the MVVM portion of your application.  You'd then just have the code to generate them in your user control, and have it "hard code" the Windows Forms drawing based off the User Control's DataContext.


    Reed Copsey, Jr. - http://reedcopsey.com
    Tuesday, November 3, 2009 12:42 AM
  • I think I see what you are saying- basically use a custom control with the graphics drawing code in the codebehind rather than the viewmodel, and let the datacontext take care of the data need.

    I will most certainly look into this.

    The other alternative would be to just fix this stuff- which is in the long range plan anyways.

    If we were to switch gears for a second and assume this is a Canvas, can I do my drawing from the ViewModel in that case?  Not sure how that would work since the ViewModel shouldnt know anything about the view.

    If this is correct, does this mean that any kind of drawing for WPF needs to happen in the codebehind, and the viewmodel just provides the data?  The last thing I want to do is put a large effort into hacking something together to work that will need a large effort to fix later on.

    Thanks for all your help by the way!
    Tuesday, November 3, 2009 1:32 AM
  • Well, the way I see it, when you draw items, you're drawing something.

    The something that you're drawing is different than the rendering itself.  The rendering is a specific "View" of the "Drawing".  So, in this case, the thing you're drawing is going to be part of your model, and the way that is drawn is really part of the View.

    That being said, I'd probably, in most cases, make some form of intermediary classes that handle putting the drawing into the Canvas, and call that from within your ViewModel.  The intermediary class would really be part of your view layer, and hopefully, work against some kind of interface (which would allow your ViewModel to stay somewhat neutral to the View, since it wouldn't need to know how the actual objects will be rendered, just say "this is what we want to draw").  Really, in essense, it would just be a custom control that knows how to draw your model (or some interface).

    If you followed this type of setup, you'd basically still be doing MVVM.  In this case, your View would just use a custom control you create for the code-based view (using WPF).  You'd still have all of the benefits of MVVM in terms of separation of concerns, usability, etc, but be doing the rendering into your specific control in code.  The control would be pure view - and kind of outside of the scope of MVVM.
    Reed Copsey, Jr. - http://reedcopsey.com
    Tuesday, November 3, 2009 2:31 AM