I made a little timer app using WPF and I wanted to put my app on the taskbar, but when I click anywhere on the taskbar, my app loses focus and the taskbar comes on top of my app, even though I have Topmost=True in the XAML code.
How my app behaves:
And Windows clock app which behaves exactly the way that I want :
Is there any way to achieve this behavior in my WPF app?
The XAML code:
<Window x:Class="MultiStopwatch.StopwatchWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:utility="clr-namespace:MultiStopwatch.Utility"
mc:Ignorable="d"
Title="MultiStopwatchWindow"
WindowStyle="None" AllowsTransparency="True" Background="Transparent" ResizeMode="NoResize"
ShowInTaskbar="False" Topmost="True" Height="28" Width="112"
utility:EnableDragHelper.EnableDrag="True">
<Window.Clip>
<RectangleGeometry Rect="0,0,112,28" RadiusX="5.5" RadiusY="5.5" />
</Window.Clip>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="assets/Icons.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Border Background="Black" CornerRadius="4">
<Grid>
<Button x:Name="StartBtn" Margin="0,0,83,0" Width="21" Height="21" Cursor="Hand"
Click="StartBtn_OnClick">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border x:Name="StartBtnBorder" Background="#333333" CornerRadius="3" Padding="3.5"
RenderTransformOrigin="0.5,0.5">
<Border.RenderTransform>
<ScaleTransform />
</Border.RenderTransform>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="StartBtnBorder"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="#454545" Duration="0:0:0.13" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="StartBtnBorder"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="#333333" Duration="0:0:0.13" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="StartBtnBorder"
Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0.9" />
<EasingDoubleKeyFrame KeyTime="0:0:0.09" Value="1" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="StartBtnBorder"
Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0.9" />
<EasingDoubleKeyFrame KeyTime="0:0:0.09" Value="1" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
<Grid>
<Image x:Name="StartBtnIcon" Source="{StaticResource StartDrawingImage}" />
</Grid>
</Button>
<Button x:Name="ResetButton" Margin="0,0,37,0" Width="21" Height="21" Cursor="Hand"
Click="ResetButton_OnClick">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border x:Name="ResetBtnBorder" Background="#333333" CornerRadius="3" Padding="3"
RenderTransformOrigin="0.5,0.5">
<Border.RenderTransform>
<ScaleTransform />
</Border.RenderTransform>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="ResetBtnBorder"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="#454545" Duration="0:0:0.15" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="ResetBtnBorder"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="#333333" Duration="0:0:0.13" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ResetBtnBorder"
Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0.9" />
<EasingDoubleKeyFrame KeyTime="0:0:0.09" Value="1" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ResetBtnBorder"
Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0.9" />
<EasingDoubleKeyFrame KeyTime="0:0:0.09" Value="1" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
<Grid>
<Image Source="{StaticResource ResetDrawingImage}" />
</Grid>
</Button>
<TextBox x:Name="FirstStopwatchTextBox" IsReadOnly="True" SelectionBrush="Transparent"
FontSize="12" BorderThickness="0" Cursor="SizeAll" TextAlignment="Center"
FontFamily="JetBrains Mono" FontWeight="SemiBold" Foreground="#DCDCDC"
Background="Transparent" Height="15" Margin="48,6,0,6" Text="00:00:00" />
</Grid>
</Border>
</Grid>
</Window>
Edit:
I've tried using the Window.Activate(); but it only works for the first click on the taskbar, and on top of that, it doesn't work nicely... it forces the focus on the app and doesn't allow the focus to be transferred to another app on the first click, which is really bad. In the gif below I tried to show how it behaves. Notice that on the first click, the app is still on top, but on the second click the app goes behind the taskbar again. And notice how the focus doesn't go onto Visual Studio on the first click, but when I click one more time, the text cursor (caret) appears on my code and the focus is now fully on Visual Studio. This doesn't happen with the Windows clock app, if you click outside the app once, the focus is immediately transferred to that other app (while it is still on top of everything).



The process is like this:
uiAccessto true.C:\WindowsorC:\Program FilesStep 1: Setting up the .manifest file
Right-click on your project, then Add Item, and in the search box at the top search for "manifest" and an item will pop up, choose that and create your app.manifest file.
In the app.manifest, you have to set
uiAccessto true in the showed line below, so my app.manifest file looks like this:After setting this true I could no longer debug my app in Visual Studio, I think it there were some ways to debug it even with
uiAccessset to true (Search for it if you really need it) but I just disabled it untill my whole app was finished and then I set it to true and publish it.Now
uiAccessrequires your app to be signed by a code signing certificate (not SSL or anything, it has to be code signing, there are different types of certificates), becauseuiAccessis a high privilaged option, you can either buy a code signing cert (which is kinda expensive), or create a self signed certificate, which is free but it's just yours, so when you want to install this app on a different PC, it will probably throw error, because it can't find the certificate that you had on your PC, but by buying CA certificates, I think Windows will automatically recognize your app and have all the certificates and stuff ready to go for you, I don't know that much about them, or you could copy the certificate that you made into their computer and install it for them too (by installing I mean copying that certificate into the Trusted Root Certification Authorities store), or create an another self signed certificate on their system, which if you're app is a whole enterprise thing, you can't do that and you have to buy a certificate (I'm thinking that is it really immpossible? because it's just some commands that I could run after the user installs my app and I could automate the process of creating that self signed certificate on their system, import it into Trusted Root Certification Authorities store, and then finally sign my app's .exe files, I think it's possible IDK) in my case, I just made the app for myself, so I just needed to use it on my own PC that's why I made a self signed cert.Step 2: Making the self signed certificate
Open PowerShell as admin, and use this command:
Example:
Now to install your self signed certificate to the Trusted Root Certificate Authorities store, you can follow these steps:
mmc.exe.Now you've installed your certificate into the Trusted Root Certification Authorities on your machine. Now you have to create the .pfx file of that certificate, because we need it to sign our .exe files.
Open PowerShell as admin again and run this command:
Example:
Step 3: Signing the .exe files
I signed both my app's installer .exe file and also the .exe file which launches the app itself. I don't know if both are needed but do it. Download the signtool from this GitHub repo (The normal way is to download it from WindowsSDK but I tried downloading from there but my installer would throw 2230 (Not enough privilage) error that I couldn't fix at all).
Extract it and navigate to that folder (...\SignTool-10.0.22621.755\x64) my Windows is 64 bits so I used the x64 folder, if yours is 32 bit go into the x86 folder. Then open a CMD window as admin, in that same folder (it should be in the same directory, if it's not, then navigate to that folder where the signtool.exe file is located).
And run this command:
For the TimeStampServerUrl part, you might need to find a valid and online one by yourself, right now the http://timestamp.sectigo.com worked fine for me, you could use it too if this answer is not really old by now.
Example:
Now your installer file is signed. NOW YOU MUST INSTALL YOUR APP INTO ONE OF THESE FOLDERS OR IT WILL NOT WORK, either
C:\WindowsorC:\Program Files.After you installed the app, lets sign the app's launcher .exe file too with the same command:
Notice that this time you have to provide the path to the .exe file which launches the app. Which must be in one of those two directories that I said.
Important Notes
If you have set
ShowInTaskbar="False"for your window in its .XAML file, then theuiAccesswon't work. It was because of some weird advanced stuff that I couldn't understand (I'd ask all of this from Bing AI by the way (on it's "Creative Mode", it might be something different now)).But don't worry cause I think I know how to fix it even if you have
ShowInTaskbar="False". You should simply listen to your window'sLoadedevent in the code behind and when the window is loaded, you should setTopMost = falseand thenTopmost = true:Done!
Helpful links: How do I create a self-signed certificate for code signing on Windows?