none
Problem Resizing MDI Form Background Image RRS feed

  • Question

  • Hi all,

    I've looked all over the web and have seen this question asked many times but not much in the ways of answers.

    My MDI application has a dialog box on it that allows the user to select an image to use as the background image for the MDIParent form.  MDIParent's BackgroundImageLayout is set to ImageLayout.Stretch and everything works as expected. At lease until I maximize the window.  Then something weird happens: The background image does indeed stretch to fill the maximized form, but another copy of the image still in the original size of the form is layered on top of it in th upper left corner.  How do I fix this problem, so that the image stretches properly without tiling over itself?

    Thanks!

    Jason

    Sunday, July 27, 2014 5:52 AM

Answers

  • If all else fails then try putting Me.Refresh inside the MDI containers SizeChanged event. I don`t have any other ideas if Cor`s suggestion does not work.   8)

    If you say it can`t be done then i`ll try it

    • Marked as answer by Jason Bodine Sunday, July 27, 2014 9:08 PM
    Sunday, July 27, 2014 3:19 PM

All replies

  • Cor,

    This is the only code involved.  As I said, it looks perfectly normal until the mdi form get maximized. There is not currently any code to handle repainting the image on resize, as  I need to know what code to add to make it stretch properly without tiling the image over itself:

                    PicPath = trvDirectory.SelectedNode.FullPath & "\" & lstFile.SelectedItem
                    With frmMain
                        .BackgroundImage = Image.FromFile(PicPath)
                        .BackgroundImageLayout = ImageLayout.Stretch
                    End With

    Thanks,

    Jason

    Sunday, July 27, 2014 9:13 AM
  • Cor,

    The form that code is on is a dialog box that closes after the form is set.  The problem is happening when the parent form gets maximized. It stretches across the client area the way it is supposed to, but it also has another copy of the image in the form's original size layered on top of the stretched image.  Right now, the only way to get rid of it is to minimize the form to the task bar, but that'll annoy users after a while lol.

    In VB6 I could do it with StretchBlt and a couple of pictureboxes on the mdi form, but that doesn't seem to be an option in .NET, lol.

    Jason

    Sunday, July 27, 2014 9:46 AM
  • Hi,

     Perhaps there is something with the way your code is doing something that is causing this. This is not the way i would do it but, using this code i can not reproduce the error.

     

    MDI Parent

    Public Class Form1
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Me.IsMdiContainer = True
        End Sub
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim f2 As New Form2
            f2.ShowDialog()
        End Sub
    End Class
    
     

     The Dialog Window

    Public Class Form2
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Using ofd As New OpenFileDialog
                ofd.Filter = "Images|*.jpg;*.png;*.bmp"
                If ofd.ShowDialog = DialogResult.OK Then
                    With Form1
                        .BackgroundImage = Image.FromFile(ofd.FileName)
                        .BackgroundImageLayout = ImageLayout.Stretch
                    End With
                End If
            End Using
        End Sub
    End Class
     

     If you can write a small example program that reproduces the error and post it so that we can test it, then we may be able to see a problem.   8)


    If you say it can`t be done then i`ll try it

    Sunday, July 27, 2014 10:09 AM
  • IronRazers:

    Here's the code on the dialog box (actually a custom form with a picturebox, combobox, treeview,listbox, and 2 buttons.  The relevant code is after Case Else.  I am not having any trouble putting image onto the MDI form.  I'm having trouble with the fact that when the parent form is maximized after the picture has been added, it stretches across, but *also* has an unstretched copy of the same picture sitting on top of the stretched image in the upper left corner of the client area.  What I need is code to force the client area of the MDI form to repaint the background image on resize so that it stretches without the other copy of the image covering it up. I would show you the screencap I made so you can see what I'm talking about, but MSDN said my account needs to be verified before I can do that. Whatever that means, lol

    Anyway, here's the code I mentioned:

        Private Sub btnInsert_Click(sender As System.Object, e As System.EventArgs) Handles btnInsert.Click
            Select Case Me.Text
                Case "Insert Picture"
                    Dim Child As Form = frmMain.ActiveMdiChild
                    If Not (Child Is Nothing) Then
                        Dim rtfDocument As RichTextBox = TryCast(Child.ActiveControl, RichTextBox)
                        If (Not rtfDocument Is Nothing) Then
                            PicPath = trvDirectory.SelectedNode.FullPath & "\" & lstFile.SelectedItem
                            Dim Img As Image = Image.FromFile(PicPath)
                            Clipboard.Clear()
                            Clipboard.SetDataObject(Img)
                            Dim imgFormat As DataFormats.Format = DataFormats.GetFormat(DataFormats.Bitmap)
                            If rtfDocument.CanPaste(imgFormat) Then
                                rtfDocument.Paste(imgFormat)
                                Clipboard.Clear()
                            Else
                                Clipboard.Clear()
                                Exit Sub
                            End If
                        End If
                    End If
    
                Case Else
                    PicPath = trvDirectory.SelectedNode.FullPath & "\" & lstFile.SelectedItem
                    With frmMain
                        .BackgroundImage = Image.FromFile(PicPath)
                        .BackgroundImageLayout = ImageLayout.Stretch
                    End With
            End Select
            Me.Close()
        End Sub

    Jason


    Sunday, July 27, 2014 11:11 AM
  • Hi,

     This is why i say you should make a new small project without all the bells and whistles that will reproduce the problem an share the code with us. Also let us know if you set any of the properties of the 2 forms in the Design tab properties. I can not reproduce this problem.

    Here is after selecting an image

     

     And here is after maximizing it.


    If you say it can`t be done then i`ll try it

    Sunday, July 27, 2014 12:12 PM
  • Cor, 

    I don't know what's wrong either, lol, but it does it consistently with any and every single image I set to the background image of the mdi form. Those six lines of code after Case Else are the only code in the project that reference the main form's background image. There is no other code anywhere else that could be interfering with it.

    The only difference, as far as I can tell, between what I am doing and what you are doing is that I do not have the dialog form set as a mdi child form.

    Jason

    Sunday, July 27, 2014 12:12 PM
  • I even tried it as a mdi child with the same result.

    Sunday, July 27, 2014 12:27 PM
  • Ironrazerz:

    I did as you suggested.  First, I did it as you did, with a regular form with a button and got the same result that you did.... no problems.  Then, I removed the button, put the code in a MenuStrip item, and set IsMdiContainer=True to change it into a MDI container form.  The problem repeated itself on the MDI Container.

    Jason

    Sunday, July 27, 2014 12:41 PM
  • Ironrazerz:

    I did as you suggested.  First, I did it as you did, with a regular form with a button and got the same result that you did.... no problems.  Then, I removed the button, put the code in a MenuStrip item, and set IsMdiContainer=True to change it into a MDI container form.  The problem repeated itself on the MDI Container.

    Jason

     Hi,

     If you look at my prior code example Form1 is set to an MDI container and Form2 is not an MDI child form, it is a standard form shown using ShowDialog. Anyways, i tried it by using a MenuStrip in Form1 to select the image and it still works with no flaws on my end so, i am not sure what the problem may be.

    Public Class Form1
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Me.IsMdiContainer = True
        End Sub
    
        Private Sub ChooseImageToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ChooseImageToolStripMenuItem.Click
            Dim f2 As New Form2
            f2.ShowDialog()
        End Sub
    End Class
    


    Public Class Form2
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Using ofd As New OpenFileDialog
                ofd.Filter = "Images|*.jpg;*.png;*.bmp"
                If ofd.ShowDialog = DialogResult.OK Then
                    With Form1
                        .BackgroundImage = Image.FromFile(ofd.FileName)
                        .BackgroundImageLayout = ImageLayout.Stretch
                    End With
                End If
            End Using
            Me.Close()
        End Sub
    End Class
    
     

     


    If you say it can`t be done then i`ll try it

    Sunday, July 27, 2014 1:38 PM
  • Ironrazerz:

    What version of Visual Studio are you using?  I'm using VS 2010 Ultimate 64-bit on two different computers, one with Windows 7 and one with Windows 8.1.  I've made test projects on both computers to test this issue and it happens under both OSes, so if you're using a different version, I can only guess they've fixed some annoying glitch that is in 2010 so that it works for you, lol.  

    I've noticed, as I said, that the problem goes away if I minimize the window to the task bar and then restore it, which is why I suspect I need code to make the image repaint onto the form on resize.

    Jason

    Sunday, July 27, 2014 2:21 PM
  • @ Jayson,

     It may be something with new versions because, i am using good old XP 32bit with VS2008 targeting .net 3.5. I would imagine that Cor is using a newer OS and a newer VS version so if you have not tried his suggestions then maybe that will work being it worked for him.  8)


    If you say it can`t be done then i`ll try it

    Sunday, July 27, 2014 3:00 PM
  • If all else fails then try putting Me.Refresh inside the MDI containers SizeChanged event. I don`t have any other ideas if Cor`s suggestion does not work.   8)

    If you say it can`t be done then i`ll try it

    • Marked as answer by Jason Bodine Sunday, July 27, 2014 9:08 PM
    Sunday, July 27, 2014 3:19 PM
  • Hi Jason,

    This has to do with the contents of a MDI form.  It doesn't matter if you are using default form instances or not...

    When you set the BackgroundImageLayout to Stretch, the form's ResizeRedraw style bit is set.  This causes the form to repaint itself whenever the size changes (including maximizing).  However, the background image is not displayed on the form... it is actually set in the internal MdiClient control instance which was implicitly added to the form when you set it to a MDI container.  So it is this control which needs to have the ResizeRedraw style bit set.

    So in the constructor of your main form, set the form to a MDI container and then explicitly set the resize redraw style bit on the MdiClient:

    Public Class Form1
        Public Sub New()
            Me.IsMdiContainer = True
            Dim client As MdiClient = CType(Me.Controls(0), MdiClient)
            GetType(MdiClient).GetMethod("SetStyle", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic).Invoke(client, {ControlStyles.ResizeRedraw, True})
    
            ' This call is required by the designer.
            InitializeComponent()
    
            ' Add any initialization after the InitializeComponent() call.
            Me.BackgroundImageLayout = ImageLayout.Stretch
            Me.BackgroundImage = Image.FromStream(System.Net.WebRequest.CreateHttp("http://social.msdn.microsoft.com/Forums/getfile/504795").GetResponse.GetResponseStream)
        End Sub
    End Class

    -EDIT-

    Note that the code goes before the call to InitializeComponent to ensure that the first control is the MDI client.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


    Sunday, July 27, 2014 5:41 PM
    Moderator
  • @ Reed,

     Just out of curiosity, why would it work on my end but, not on OP`s end? Does it have something to do with the OS`s or maybe the Framework versions being different?  8)


    If you say it can`t be done then i`ll try it

    Sunday, July 27, 2014 6:03 PM
  • @ Reed,

     Just out of curiosity, why would it work on my end but, not on OP`s end? Does it have something to do with the OS`s or maybe the Framework versions being different?  8)


    If you say it can`t be done then i`ll try it

    Ah - it is Framework 3.5.  This may actually then qualify as a bug in Framework 4+.

    I don't know if there is reference source available for 3.5 but it would seem that setting the BackgroundImageLayout causes the form to pass the style bit onto the mdi client instance (if there is one).  This is not the behavior in 4.5... I got the exact same results as Jason when testing on Win7/4.5 and it was the 4.5 reference source I was looking at.

    But I just changed my test project to target 3.5 and then it worked as expected without implicitly setting the style bit on the MDI client instance.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Proposed as answer by IronRazerz Sunday, July 27, 2014 6:21 PM
    Sunday, July 27, 2014 6:13 PM
    Moderator
  • @ Reed,

     I figured there must be something to do with the Framework but, i didn`t want to stick my foot in my mouth by telling OP that it was. Thanks for the answer. I will try remembering that if i see this problem again.   8)


    If you say it can`t be done then i`ll try it

    Sunday, July 27, 2014 6:20 PM
  • @Reed

    I miss the reason why you use late binding in your sample. In this thread I've showed it already working well using early binding.

    @IronRazer

    Why do you propose the reply from Reed as answer, it misses very much as it is about using MDI containers.


    Success
    Cor



    Late binding is irrelevant; that code would execute once in the lifetime of the application so it doesn't hurt anything.  It is the simplest way to call the internal method on the MdiClient instance.

    The point is that there is some kind of bug here with either Framework 4.5 or VS.  Because after changing my project to target 3.5, I cannot reproduce the error at all.  I've even rebooted and started a fresh project in 4.5... but now it works just as expected regardless of where/how you set the background image layout and picture.  So it appears that you need an installation of VS2013/2010(/2012?) which has never created a project targeting a framework lower than 4.5.

    @Jason:

    Can you try changing your project to target Framework 3.5 and then change it back and see if the issue persists?

    This is the first time I've run across something like this where I could reproduce the issue exactly as described at one moment and then have that behavior completely disappear the next.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"



    Sunday, July 27, 2014 6:50 PM
    Moderator
  • @ Cor,

    "Why do you propose the reply from Reed as answer, it misses very much as it is about using MDI containers."

     Because, you and i both said we could not reproduce the same problem and OP said both of our codes where not fixing it for him. Reed said he did reproduce the same problem and that was how he fixed it. Did you reproduce the same problem and do you have a way to fix it that OP didn`t already say would not work?


    If you say it can`t be done then i`ll try it

    Sunday, July 27, 2014 6:55 PM
  • I try all day to tell that probably there is a problem with the static way (c terms) of using a form (application framework or so called My class code) in VB without making it to difficult for those who don't even know about what I'm writing with that. 

    In your code you also use "me", the OP uses the static format "Form1" in his code instead of that.

    Your and mine information makes that not impossible.



    Success
    Cor


    Again, this is completely irrelevant.  In all my testing I have used both the implicit form instance, as well as an explicit one which I passed to the dialog myself.  In both cases the results were the same; first it did not work, and now it does.

    At this point your posts are trolling - you are posting only to argue with another contributor and are offering no actual value of your own to the thread.  This has happened in more than one thread to which I've contributed and it is mostly just cluttering up the forums so I'll ask you to please stop.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Sunday, July 27, 2014 7:03 PM
    Moderator
  • Just confirming that this:

    Public Class Form1
        Public Sub New()
            ' This call is required by the designer.
            InitializeComponent()
        End Sub
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.IsMdiContainer = True
    
            ' Add any initialization after the InitializeComponent() call.
            Using dlg As New TestDialog
                dlg.ShowDialog()
            End Using
        End Sub
    End Class
    
    Public Class TestDialog
        Inherits Form
        Private WithEvents Button1 As New Button With {.AutoSize = True, .Text = "Test"}
    
        Public Sub New()
            Controls.Add(Button1)
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            With Form1
                .BackgroundImageLayout = ImageLayout.Stretch
                .BackgroundImage = Image.FromStream(System.Net.WebRequest.CreateHttp("http://social.msdn.microsoft.com/Forums/getfile/504795").GetResponse.GetResponseStream)
            End With
            Me.DialogResult = Windows.Forms.DialogResult.OK
            Me.Close()
        End Sub
    End Class
    Now works exactly as expected (whereas prior to the switch to 3.5 it would fail to redraw correctly).

    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Sunday, July 27, 2014 7:57 PM
    Moderator
  • Ironrazers and all,

    Putting Me.Refresh in the SizeChanged event worked like a charm!!!! :)  Thank you guys for being so patient with me.  I'm still learning the .NET version of Visual Studio and it's a slow-going process LOL!

    Jason

    Sunday, July 27, 2014 9:09 PM
  • Ironrazers and all,

    Putting Me.Refresh in the SizeChanged event worked like a charm!!!! :)  Thank you guys for being so patient with me.  I'm still learning the .NET version of Visual Studio and it's a slow-going process LOL!

    Jason

     Your Welcome. Glad it helped.  8)

     By the way, did you read Reed`s post about building your app to targeting the .net framework 3.5 and then setting it back to target the 4.0 or 4.5 .net framework?  Just curious if it would work for you so that you wouldn`t need to use the Me.Refresh fix.

     Or

     Try Cor`s idea of using With Me.Parent instead of using the main form name like With frmMain to see if that worked?


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Sunday, July 27, 2014 9:39 PM
    Sunday, July 27, 2014 9:29 PM
  • I did try it Cor's way but got the same result, lol.  And Reed's suggestion was the next thing I was gonna try if Me.Refresh didn't work. :)
    Sunday, July 27, 2014 9:47 PM
  • I did try it Cor's way but got the same result, lol.  And Reed's suggestion was the next thing I was gonna try if Me.Refresh didn't work. :)

     Alright, thanks. I was just curios.  8)

    If you say it can`t be done then i`ll try it

    Sunday, July 27, 2014 9:58 PM
  • @IronRazerz,

    While busy with testing the code from Jason, I saw what he does probably wrong. 

    However, I don't add anymore to this thread. With replies like "got the same result" while I proof in this thread with images how it works, I can do nothing. 


    Success
    Cor


    Sunday, July 27, 2014 10:52 PM
  • Private Sub frmMain_Resize(sender As Object, e As EventArgs) Handles Me.Resize, Me.SizeChanged Dim ctlMDI As MdiClient For Each ctl In Me.Controls Try ctlMDI = CType(ctl, MdiClient) DirectCast(ctlMDI, MdiClient).Refresh() Exit For Catch exc As InvalidCastException End Try Next End Sub


    Tuesday, June 30, 2020 11:03 PM