Asked  10 Months ago    Answers:  5   Viewed   10 times

I wanted to have a customized window so followed a few tutorials which enable this by setting the window style to none, and then adding the title-bar/restore/minimize/close buttons yourself. The minimize is achieved by simply handling the click event and setting the Window-state to minimized, but this doesn't show the minimize animation you see on Windows 7, and just instantly hides the window, which feels very odd when used with other windows that do animate, as you tend to feel the application is closing.

So, is there anyway of enabling that animation? .. it seems to be disabled when you change the WindowStyle to none.

Edit : Test code

public partial class MainWindow : Window
{
    public MainWindow()
    {
        WindowStyle = WindowStyle.None;
        InitializeComponent();
    }

    [DllImport("user32.dll")]
    static extern int SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
        base.OnMouseLeftButtonDown(e);

        // this doesnt seem to animate
        SendMessage(new WindowInteropHelper(this).Handle, 0x0112, (IntPtr)0xF020, IntPtr.Zero);
    }

    protected override void OnMouseRightButtonDown(MouseButtonEventArgs e)
    {
        base.OnMouseRightButtonDown(e);

        WindowStyle = WindowStyle.SingleBorderWindow;
        WindowState = WindowState.Minimized;
    }

    protected override void OnActivated(EventArgs e)
    {
        base.OnActivated(e);

        Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() => WindowStyle = WindowStyle.None));
    }
}

 Answers

4

Edited the answer after experimenting a bit.

There are two options: 1. You can change the Style just before minimising and activating the window:

private void Button_OnClick(object sender, RoutedEventArgs e)
{
    //change the WindowStyle to single border just before minimising it
    this.WindowStyle = WindowStyle.SingleBorderWindow;
    this.WindowState = WindowState.Minimized;
}

private void MainWindow_OnActivated(object sender, EventArgs e)
{
    //change the WindowStyle back to None, but only after the Window has been activated
    Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() => WindowStyle = WindowStyle.None));
}

This solution has one limitation - it doesn't animate the window if you minimise it from the taskbar.

2. Minimise the Window by sending it WM_SYSCOMMAND message with SC_MINIMIZE parameter and changing the border style by hooking into the message (HwndSource.FromHwnd(m_hWnd).AddHook(WindowProc)).

internal class ApiCodes
{
    public const int SC_RESTORE = 0xF120;
    public const int SC_MINIMIZE = 0xF020;
    public const int WM_SYSCOMMAND = 0x0112;
}

private IntPtr hWnd;

[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);


private void Window_Loaded(object sender, RoutedEventArgs e)
{
    hWnd = new WindowInteropHelper(this).Handle;
    HwndSource.FromHwnd(hWnd).AddHook(WindowProc);
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    SendMessage(hWnd, ApiCodes.WM_SYSCOMMAND, new IntPtr(ApiCodes.SC_MINIMIZE), IntPtr.Zero);
}

private IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    if (msg == ApiCodes.WM_SYSCOMMAND)
    {
        if (wParam.ToInt32() == ApiCodes.SC_MINIMIZE)
        {
            WindowStyle = WindowStyle.SingleBorderWindow;
            WindowState = WindowState.Minimized;
            handled = true;
        }
        else if (wParam.ToInt32() == ApiCodes.SC_RESTORE)
        {
            WindowState = WindowState.Normal;
            WindowStyle = WindowStyle.None;
            handled = true;
        }
    }
    return IntPtr.Zero;
}

Neither of the above methods are great, because they are just hacks. The biggest downside is that you can actually see the border reappearing for a moment when you click the button. I'd like to see what others come up with as I don't consider this as a good answer myself.

Wednesday, August 11, 2021
 
Abdel
 
3

This is actually by design. Elements that do not derive from Control will not pick up implicit Styles, unless they are in the application resources.

This link explains this in more detail, or you can view the Connent bug report.

Thursday, June 10, 2021
 
Parfait
 
4

The programs remove the non-client area (the title bar) and have a bunch of custom handling for reproducing the window buttons, icons, system menu etc. The benefit of this is that they can draw to the new "title bar", which is actually part of the standard client area, adding tabs or other custom controls.

The following two articles will show you how to do this on Vista and above (using the DWM):

  • Setting up a custom title bar on Windows Vista / 7
  • Setting up a custom title bar - reprise This one has a demo app showing the result of a number of variations / options.

This is very complex to do and get right, so the above two articles are invaluable. The author must have put a lot of work into them! Both links have example code written in Delphi, but it should be easy enough to translate it to C++ - the concepts are identical, it's just syntax.

You might also be interested in general resources on Glass and DWM, since it's all closely related. You'll spot the above two links included in that list :)

Sunday, August 1, 2021
 
Gili
 
5

This is actually much more difficult than it appears. In WPF, a Label is not a TextBlock. It derives from ContentControl and can therefore host other, non-text controls in its Content collection.

However, you can specify a string as the content as in the example below. Internally, a TextBlock will be constructed to host the text for you.

<Label Content="Test!"/>

This internally translates to:

    <Label>
        <Label.Content>
            <TextBlock>
                Test!
            </TextBlock>
        </Label.Content>
    </Label>

The simple solution to this would be for the TextDecorations property of a TextBlock to be an attached property. For example, FontSize is designed this way, so the following works:

    <Label TextBlock.FontSize="24">
        <Label.Content>
            <TextBlock>
                Test!
            </TextBlock>
        </Label.Content>
    </Label>

The TextBlock.FontSize attached property can be applied anywhere in the visual tree and will override the default value for that property on any TextBlock descendant in the tree. However, the TextDecorations property is not designed this way.

This leaves you with at least a few options.

  1. Use color, border, cursor, etc., instead of underlined text because this is 100% easier to implement.
  2. Change the way you are doing this to apply the Style to the TextBlock instead.
  3. Go to the trouble to create your own attached property and the control template to respect it.
  4. Do something like the following to nest the style for TextBlocks that appear as children of your style:

FYI, this is the ugliest thing I've done in WPF so far, but it works!

    <Style x:Key="ActionLabelStyle" TargetType="{x:Type Label}">
        <Setter Property="Margin" Value="10,3" />
        <Setter Property="Padding" Value="0" />
        <Setter Property="TextBlock.TextWrapping" Value="Wrap" />
        <Setter Property="FontFamily" Value="Calibri" />
        <Style.Triggers>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="IsMouseOver" Value="True" />
                    <Condition Property="IsEnabled" Value="True" />
                </MultiTrigger.Conditions>
                <Setter Property="Background" Value="Red" />
            </MultiTrigger>
        </Style.Triggers>
        <Style.Resources>
            <Style TargetType="TextBlock">
                <Style.Triggers>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Label}, Path=IsMouseOver}" Value="True" />
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled}" Value="True" />
                        </MultiDataTrigger.Conditions>
                        <Setter Property="TextDecorations" Value="Underline"/>
                    </MultiDataTrigger>
                </Style.Triggers>
            </Style>
        </Style.Resources>
    </Style>

This works because it is overriding the default style of any TextBlock beneath a Label of this style. It then uses a MultiDataTrigger to allow relative binding back up to the Label to check if its IsMouseOver property is True. Yuck.

Edit:

Note that this only works if you explicitly create the TextBlock. I was incorrect when I posted this because I had already dirtied up my test Label. Boo. Thanks, Anvaka, for pointing this out.

    <Label Style="{StaticResource ActionLabelStyle}">
        <TextBlock>Test!</TextBlock>
    </Label>

This works, but if you have to go to this trouble, you're just working too hard. Either someone will post something more clever, or as you said, my option 1 is looking pretty good right now.

Friday, October 29, 2021
 
Rechlay
 
2

use the bitwise & operator to compare with that long type,

example

if (szLng & WS_CAPTION){
    // that window has caption
}
Thursday, November 11, 2021
 
Johnson
 
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :