A teammate came to talk to me, because he’s working with a semi-transparent window, with no Border, and he wants to be able to resize it. Allowing a user to move, minimize, maximize and close it are easy, but how to resize?
Well, this is actually pretty easy. There is a property on the Window named ResizeMode, and if you set it to “CanResizeWithGrip”, then a ResizeGrip control is placed on your window automatically, and if you run the app, it will, correctly, resize your window.
But, the default grip is six small squares arranged in a SE-pointing triangle. And, if you look in Blend, that control isn’t actually in the XAML, so there’s no way to modify it. You can’t even make it transparent to put a customized control ‘under’ it. And it’s magical, in that it you can’t possibly get another control on top of it, even with Bring To Front… So, how do you customize the look and feel of that control?
You’ll find that you can create a new ResizeGrip control, and place it in the bottom right, but you will find that it will be rendered under this mystical ResizeGrip, so no customization there either…
Under the covers, here’s the problem. That ResizeGrip is not ‘technically’ part of the Window. Just as WPF is about to instantiate the window, it sees that the ResizeMode is set to CanResizeWithGrip, and it creates that grip for you in the SE corner. It simply instantiates the control, sets the properties to show up in the bottom left, and that’s it. Unfortunately, this means that you can’t modify any of the properties on it, since it’s actually created when the Window is Instantiated.
I suppose, if you wanted to, you could, in code, track down that control by looking at the children of the Window, although I’m not even sure it *IS* technically even there.
You could also create your own custom control (probably inherited from Thumb), and implement all your own MouseDown/Up/Move code to do your resizing for you.
Thankfully, here’s a better solution. Drop a ResizeGrip somewhere on your document, and edit a copy of the template. But, when the dialog comes up to let you know that you’re creating a new Template, click the “Apply To All” radio button, instead of supplying a name. By specifying Apply To All, you’re telling WPF that any new controls of this type, unless they specify a new template, should use the template that you’re creating at this moment. Go ahead and trick out the ResizeGrip however you want in the Template, then delete the ResizeGrip that you created at the beginning of this process.
Now, you’ve got a new default ResizeGrip template, so now when WPF instantiates that ResizeGrip, it gets your new default template, and gets the look and feel you want.
The obvious question, now, is that once you’ve done this, what if you want different ResizeGrips for different areas of your window? I.e. maybe my dialogs that show names have a resize grip with a yellow smiley face, but my dialogs for error messages show a little horned devil.
Two points here… First, when you define your new default template, you can specify the scope. So, if you scope your new template to the Application, then ALL your ResizeGrips will look identical. However, if you scope it to individual windows, those windows can have different templates.
Second, there’s nothing stopping you from creating a template whose appearance is a transparent block. Then, you can simply put whatever you want your grip to look like at the bottom right, and the real resize grip will be rendered on top, but since it’s transparent, you won’t see it… you’ll just get the functionality. Of course, if you’re going to try this route, make sure your little smiley faces or whatever are laid out in such a way that they’ll stay at the bottom right :).
PS: If folks don’t know how to set up moving/close/minimize behavior on transparent windows, give me a shout, and I’ll put something here for those scenarios.