WPF Thumb drag and move with WindowState.Maximized - c#

I have custom window with WindowState=WindowState.Maximized with border and thumb inside in the border, it seems that when the WindowState=WindowState.Maximized I cannot drag and move the custom window to different screen.
Xaml:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="350"
Width="525"
WindowStyle="None">
<Border Name="headerBorder"
Width="Auto"
Height="50"
VerticalAlignment="Top"
CornerRadius="5,5,0,0"
DockPanel.Dock="Top"
Background="Red"
BorderThickness="1,1,1,1"
BorderBrush="Yellow">
<Grid x:Name="PART_Title">
<Thumb x:Name="headerThumb"
Opacity="0"
Background="{x:Null}"
Foreground="{x:Null}"
DragDelta="headerThumb_DragDelta"/>
</Grid>
</Border>
</Window>
C#:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
WindowState = System.Windows.WindowState.Maximized;
}
private void headerThumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
Left = Left + e.HorizontalChange;
Top = Top + e.VerticalChange;
}
}
I've also overridden MouseLeftButtonDown method and using DragMove() inside but without success. I've also tried to subscribe to thumb's MouseLeftButtonDown and write there DragMove() but without success.

By default, maximized windows cannot be moved, thus Left and Top have no effect. One option would be to register to the Thumb.DragStarted event and check if the window is maximized. If yes, you can set WindowState.Normal and successively update the Left and Top properties.
In code, this would look somewhat like this:
private void Thumb_OnDragStarted(object sender, DragStartedEventArgs e)
{
// If the window is not maximized, do nothing
if (WindowState != WindowState.Maximized)
return;
// Set window state to normal
WindowState = WindowState.Normal;
// Here you have to determine the initial Left and Top values
// for the window that has WindowState normal
// I would use something like the native 'GetCursorPos' (in user32.dll)
// function to get the absolute mouse point on all screens
var point = new Win32Point();
GetCursorPos(ref point);
Left = point - certainXValue;
Top = point - certainYValue;
}
You can learn more about GetCursorPos here.
However, I would strongly advise you to use the WindowChrome class that comes with .NET 4.5 and that was also suggested by Max in the comments. You just have to use the following code and you have the functionality you're asking for:
<Window x:Class="ThumbMaximizedWindow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350"
Width="525"
WindowStyle="None"
WindowState="Maximized">
<WindowChrome.WindowChrome>
<WindowChrome />
</WindowChrome.WindowChrome>
</Window>

Related

UIElement.ManipulationDelta only Triggers Once on C# WPF

I want to implement an UI for finger controling, in WPF C# .Net framework, VS2019.
ManipulationDelta event is added on a Rectangle and it supposed to work continiously. But when I test it, it triggered only once at the moment I tapped(touch down). This event should be triggered continuously while my finger pressing.
Target: Show the position of pointer within the rectangle area.
XAML:
<Window x:Class="WpfApp5.MainWindow"
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:local="clr-namespace:WpfApp5"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid Margin="0,0,-322,-112">
<Rectangle
ManipulationDelta="Rectangle_ManipulationDelta"
TouchMove="Rectangle_TouchMove"
Fill="#FFF4F4F5"
HorizontalAlignment="Left"
Height="274" Margin="162,70,0,0"
Stroke="Black"
VerticalAlignment="Top"
Width="582" IsManipulationEnabled="True"/>
<TextBlock
x:Name="textBlock"
HorizontalAlignment="Left"
TextWrapping="Wrap"
VerticalAlignment="Top"
Margin="31,26,0,0"><Run Text="TextBlock"/></TextBlock>
</Grid>
Here is the event to print the postion of finger:
C#:
namespace WpfApp5{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Rectangle_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
}
private void Rectangle_TouchMove(object sender, TouchEventArgs e)
{
textBlock.Text = "Manipulation Touch: " + Mouse.GetPosition(Application.Current.MainWindow).ToString();
}
}
}
UI tested on Windows10 Simulator v16 and Surface Pro
Holding right-clicking is disabled
A test video is here to describe the issue with subtitle
Test Video
After testing, the event likes TouchMove, MouseMove, ManipulationDelta will be fired only if the cursor "get into" the border of element. I want to trigger this event within target area. Or should I use another event to achieve this?
Any suggestion is appreciated! Thank you.
I found that I use worng event, I should use TouchMove instead of ManipulationDelta(manipulation means manipulation for translation, zoom, etc, it's not necessary in this case).
And the flag should be set to false:
IsManipulationEnabled="false"
It working now! And thanks for who paticipating this discussion.

Window.show not loading contents in wpf

I am trying to bring up a window as a loading screen using the system.windows.window.show() method. The program is supposed continue running code and then close the window after it is done. The problem is that the window will not show the textblock I am trying to display. But when I do ShowDialog() it will
LoadingWindow lw = new LoadingWindow();
lw.Show();
//
//do stuff
//
lw.Close();
<Window x:Class="RevitAPITest3.LoadingWindow"
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:local="clr-namespace:RevitAPITest3"
mc:Ignorable="d"
Title="Loading..." Height="450" Width="800" >
<Grid>
<TextBlock x:Name="text" FontSize="20" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Height="43" Width="291">testing</TextBlock>
</Grid>
</Window>
There's a fundamental difference between lw.Show() and lw.ShowDialog().
lw.Show() will immediately return to the next line of code without waiting for the window to close.
lw.ShowDialog() will wait for the window to close manually by the user, then return a value of true/false.
In your example code, your problem is that because lw.Show() returns immediately, it will then "do stuff" and then call lw.Close() which closes your window before you even see the window.
What you'll want to do is something like this. Notice: You never have to explicitly call lw.Close() because the window will automatically be closed as soon as it completes the lw.ShowDialog() line.
var result = lw.ShowDialog();
if (result.HasValue)
{
//
//do Stuff
//
}
Here is a complete working solution. Check to see where you are doing things differently and see if you can match this implementation.
MainWindow.xaml
<Window x:Class="LoadingWindowTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="768" Width="1024" WindowStartupLocation="CenterScreen">
<Grid>
<TextBlock Text="Main Window" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="32"/>
</Grid>
</Window>
MainWindow.xaml.cs
using System.Threading.Tasks;
using System.Windows;
namespace LoadingWindowTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private LoadingWindow lw;
public MainWindow()
{
InitializeComponent();
this.Loaded += OnLoaded;
}
private async void OnLoaded(object sender, RoutedEventArgs e)
{
// Make the main window hidden until loading is done
this.Visibility = Visibility.Hidden;
// Show the Loading window
lw = new LoadingWindow();
lw.Show();
// Simulate a long running task
await Task.Delay(5000);
// Close the Loading window
lw.Close();
// Show the Main Window
this.Visibility = Visibility.Visible;
}
}
}
LoadingWindow.xaml (no xaml.cs shared because I didn't touch it)
<Window x:Class="LoadingWindowTest.LoadingWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="LoadingWindow" Height="450" Width="800" WindowStartupLocation="CenterScreen">
<Grid>
<Grid>
<TextBlock x:Name="text" FontSize="20" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Height="43" Width="291">testing</TextBlock>
</Grid>
</Grid>
</Window>
Build and Run, then this is the Expected Output:
You should see the LoadingWindow on the center of the screen, then after 5 seconds, it closes and the MainWindow shows.

AutoResize MainWindow after user resizes window

I have a Window defined as follows:
<Window x:Class="AutomatedSQLMigration.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
SizeToContent="Height"
DataContext="{Binding MainPageViewModel, Source={StaticResource Locator}}">
<DockPanel Name="MasterDockPanel">
...
</DockPanel>
</Window>
I have a number of tabs in a tab control and the window correctly resizes the height to fit the content of the selected tab as long as the user does not change the window size. Once the user changes the window size manually, the window will not resize itself to fit the content of the selected tab.
What can I do to get the window to resize automatically even after the user has manually changed the size?
As far as I know, you required behavior outside the box, so I can see these solutions:
Set the minimum Height for the Window (like this <Window MinHeight="150" ...), in order the user can not change the Height is less than the specified minimum content of TabControl. I think this is the most simple and reliable solution.
Use a hack like this:
XAML
<Window x:Class="AutoResizeProblem.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
Loaded="Window_Loaded"
SizeToContent="Height">
<DockPanel Name="MasterDockPanel" Background="Aquamarine">
<TabControl SelectionChanged="TabControl_SelectionChanged">
<TabItem Header="Test1">
<TextBlock Name="Test1Content" Background="Red" Height="100">TEST1</TextBlock>
</TabItem>
<TabItem Header="Test2">
<TextBlock>TEST2</TextBlock>
</TabItem>
<TabItem Header="Test3">
<TextBlock>TEST3</TextBlock>
</TabItem>
</TabControl>
</DockPanel>
</Window>
Code-behind
public partial class MainWindow : Window
{
double _initWindowHeight = 0;
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_initWindowHeight = this.Height;
}
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (_initWindowHeight > 0)
this.Height = _initWindowHeight;
}
}
In this case, you save the initial Height of the Window in Loaded event. Then, when you change tabs (SelectionChanged event) is assigned to the saved value for the Window.

How to create an automatic animated carousel cyling images using C# or XAML?

I have done carousels in web development, but animating them in WPF through XAML or C# is new to me. There are examples on the web, but they either are outdated or not what I am looking for. Even when I play around with source code of other projects, it's not what I hope for.
I want to have images sliding left-to-right (horizontally) automatically. The user cannot interact with the images to stop the sliding. While I can do this manually in a ScrollViewer, the process is manual...
ScrollViewer doesn't have any dependencies for animation. I tried using this to see if it is possible, but the application would always crash. Example I used..
Another attempt I've tried is storing images in a StackPanel, making sure the StackPanel is the width of one of my images, then having DispatcherTimer set to animate the TranslateTransform's X property. But...that didn't go anywhere.
Using a ScrollViewer or StackPanel is not important at all. I just want to have a carousel-like effect automatically transitioning through images. Sort of like THIS
I'm currently using Visual Studio 2012 and 2013, if it helps.
Is there a way to do this?
I' ve prepared exemplary carousel in wpf. You might want to use the code in form of UserControl for instance. As you proposed I prepared carousel with use of StackPanel. Code of my form looks as follows:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Storyboard x:Key="CarouselStoryboard">
<DoubleAnimation
Storyboard.TargetName="CarouselTransform"
Storyboard.TargetProperty="X"/>
</Storyboard>
</Window.Resources>
<Canvas>
<StackPanel Name="Carousel" Orientation="Horizontal">
<StackPanel.RenderTransform>
<TranslateTransform x:Name="CarouselTransform" />
</StackPanel.RenderTransform>
<Button Height="350" Width="525" Content="Page1"/>
<Button Height="350" Width="525" Content="Page2"/>
<Button Height="350" Width="525" Content="Page3"/>
</StackPanel>
<Button Click="Left_Click" Content="Left" HorizontalAlignment="Left" Margin="10,164,0,0" VerticalAlignment="Top" Width="45">
</Button>
<Button Click="Right_Click" Content="Right" HorizontalAlignment="Left" Margin="448,170,0,0" VerticalAlignment="Top" Width="45"/>
</Canvas>
</Window>
The Storyboard element within WindowResources defines animation to be performed. It will change X property of TranslationTransform applied to StackPanel "Carousel" - this will result in animated movement of that panel. 3 buttons within the panel simulates 3 panels of the carousel. At the bottom there are 2 buttons - one for moving left and second for moving right. There are callback methods bounded to them. Code behind of the form looks like that:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private int currentElement = 0;
private void Left_Click(object sender, RoutedEventArgs e)
{
if(currentElement < 2)
{
currentElement++;
AnimateCarousel();
}
}
private void Right_Click(object sender, RoutedEventArgs e)
{
if (currentElement > 0)
{
currentElement--;
AnimateCarousel();
}
}
private void AnimateCarousel()
{
Storyboard storyboard = (this.Resources["CarouselStoryboard"] as Storyboard);
DoubleAnimation animation = storyboard.Children.First() as DoubleAnimation;
animation.To = -this.Width * currentElement;
storyboard.Begin();
}
}
currentElement field holds information which panel is currently being displayed to the user. Method AnimateCarousel actualy starts the animation. It refers to Storyboard defined in Resources and sets its DoubleAnimation To property to the value to which Carousel panel should be moved. Then by calling Begin method on storyboard it performs animation.

Bringing a user control to the front in Expression Blend, C#, WPF

I have a window with a Grid on.
On this I have some buttons, one of which when clicked will create a new 'PostIt' which is a user control I have created.
What I want to do is click on a 'PostIt' and have that control on top of all the others.
I have tried...
Grid.SetZIndex(sender, value);
Which seems to be the correct code, no errors, just not movement of the control :(
The problem may lie in the fact that the code for the click is in the user control and not the mainwindow cs file. Does this matter?
The 'PostIt' is simply a border with a text box in it.
Are you calling Grid.SetZIndex(sender, value) in a handler of the PostIt mouse click, or a handler for a control inside the PostIt? What is the value that you are setting?
Here is an example that works:
<UserControl x:Class="WpfApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" MouseUp="UserControl_MouseUp">
<Grid>
</Grid>
</UserControl>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private void UserControl_MouseUp(object sender, MouseButtonEventArgs e)
{
Panel.SetZIndex(this, Panel.GetZIndex(this) + 2);
}
}
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:UserControl1 Background="Green" Margin="40,40,100,100" Panel.ZIndex="0" />
<local:UserControl1 Background="Red" Margin="140,140,10,10" Panel.ZIndex="1" />
</Grid>
</Window>
Jogy
This may not be the best solution, but it's the one that worked for me; I was re-ordering two grids:
GridOnBottom.SetValue(Grid.ZIndexProperty, (int)GridOnTop.GetValue(Grid.ZIndexProperty) + 1);
...with GridOnBottom and GridOnTop renamed to the instances of the objects you're re-ordering. Granted, it's not the best solution, but it works.

Categories