In an empty WPF Project first I've deleted everything except AssemblyInfo.cs
, then added App.cs
, where I start the app, and four other windows. RootWindow
acts as the positioner/resizer of three other windows, TopWindow
, MiddleWindow
and BottomWindow
. These three windows are identical, all they have is a constructor with these:
class MiddleWindow : Window
{
public MiddleWindow() {
Title = "Middle";
ResizeMode = ResizeMode.NoResize;
AllowsTransparency = true;
WindowStyle = WindowStyle.None;
ShowInTaskbar = false;
}
}
in the RootWindow
, I've three Rectangle
, topRect, midRect, botRect, and in its ArrangeOverride
I set the Top, Left, Width and Height of those three Windows based on the position of those Rectangles. Here's what happens when I run the app:
initially there's always a gap between the MiddleWindow
and BottomWindow
, As I resize the RootWindow
those windows resizes sometimes with the gap and other times without gap. If I maximize and restore the RootWindow
, those three also resize accordingly and when I move the RootWindow
, they also move along. The problem arises when I click on any of those three windows or minimize the RootWindow
. If I click on any of those three, all three starts blinking and all of them disappears eventually!
In the OnDeactivated
of the RootWindow
, I hide those so they become invisible and in the OnActivated
of the RootWindow
, I set Visibility of those to Visible BUT only the last one appears when I restore the RootWindow
by clicking on taskbar!
Here's the RootWindow.cs
:
class RootWindow : Window
{
double radius = 5;
Border windowBorder, titleBar;
Grid contentGrid, titlebarIconGrid, rectGrid;
ActionButton close, minimize, maxRestore;
Rectangle topRect, midRect, botRect;
public TopWindow TopWin { get; set; }
public MiddleWindow MidWin { get; set; }
public BottomWindow BotWin { get; set; }
public RootWindow() {
Height = 800;
Width = 1200;
WindowStartupLocation = WindowStartupLocation.CenterScreen;
WindowStyle = WindowStyle.None;
AllowsTransparency = true;
WindowChrome.SetWindowChrome(this, new WindowChrome() {
ResizeBorderThickness = new Thickness(0, 0, 5, 5),
CaptionHeight = 0
});
addTitleIcons();
titleBar = new Border() {
CornerRadius = new CornerRadius(radius, radius, 0, 0),
Background = Brushes.LightGray,
Height = 32,
Effect = new DropShadowEffect() { BlurRadius = 5, Opacity = 0.5, Direction = -90 },
Child = titlebarIconGrid
};
initRects();
Grid.SetRow(rectGrid, 1);
contentGrid = new Grid() {
RowDefinitions = {
new RowDefinition() { Height = GridLength.Auto },
new RowDefinition()
},
Children = { titleBar, rectGrid }
};
windowBorder = new Border() {
Background = Brushes.Transparent,
CornerRadius = new CornerRadius(radius),
BorderThickness = new Thickness(1),
BorderBrush = Brushes.LightBlue,
Child = contentGrid
};
AddVisualChild(windowBorder);
titleBar.MouseLeftButtonDown += handleResize;
titleBar.MouseMove += move;
Loaded += onLoaded;
}
void onLoaded(object sender, RoutedEventArgs e) {
TopWin.Dispatcher.Invoke(TopWin.Show);
MidWin.Dispatcher.Invoke(MidWin.Show);
BotWin.Dispatcher.Invoke(BotWin.Show);
}
void initRects() {
topRect = new Rectangle()/* { IsHitTestVisible = false }*/;
midRect = new Rectangle()/* { IsHitTestVisible = false }*/;
botRect = new Rectangle()/* { IsHitTestVisible = false }*/;
Grid.SetRow(midRect, 1);
Grid.SetRow(botRect, 2);
rectGrid = new Grid() {
IsHitTestVisible = false,
RowDefinitions = {
new RowDefinition(),
new RowDefinition(),
new RowDefinition()
},
Children = { topRect, midRect, botRect }
};
}
void move(object sender, MouseEventArgs e) {
if (e.LeftButton == MouseButtonState.Pressed) {
DragMove();
InvalidateArrange();
}
}
void handleResize(object sender, MouseButtonEventArgs e) {
if (e.ClickCount == 2) resize();
}
void addTitleIcons() {
close = new ActionButton() {
Width = 24,
Height = 24,
ToolTip = "Close",
Margin = new Thickness(0, 0, 5, 0),
Icon = Icons.CloseCircle,
Command = Application.Current.Shutdown
};
maxRestore = new ActionButton() {
Width = 18,
Height = 18,
ToolTip = "Maximize",
Margin = new Thickness(0, 0, 5, 0),
Icon = Icons.Maximize,
Command = resize
};
minimize = new ActionButton() {
Width = 18,
Height = 18,
ToolTip = "Minimize",
Margin = new Thickness(0, 0, 5, 0),
Icon = Icons.Minimize,
Command = () => WindowState = WindowState.Minimized
};
Grid.SetColumn(close, 3);
Grid.SetColumn(maxRestore, 2);
Grid.SetColumn(minimize, 1);
titlebarIconGrid = new Grid() {
ColumnDefinitions = {
new ColumnDefinition(),
new ColumnDefinition(){ Width = GridLength.Auto },
new ColumnDefinition(){ Width = GridLength.Auto },
new ColumnDefinition(){ Width = GridLength.Auto }
},
Children = { close, maxRestore, minimize }
};
}
void resize() {
if (WindowState == WindowState.Maximized) {
ResizeMode = ResizeMode.CanResizeWithGrip;
WindowState = WindowState.Normal;
maxRestore.Icon = Icons.Maximize;
maxRestore.ToolTip = "Maximize";
}
else {
ResizeMode = ResizeMode.NoResize;
WindowState = WindowState.Maximized;
maxRestore.Icon = Icons.Restore;
maxRestore.ToolTip = "Restore";
}
}
protected override Size ArrangeOverride(Size arrangeBounds) {
windowBorder.Width = arrangeBounds.Width;
windowBorder.Height = arrangeBounds.Height;
windowBorder.Measure(arrangeBounds);
windowBorder.Arrange(new Rect(windowBorder.DesiredSize));
double width = topRect.ActualWidth;
double height = topRect.ActualHeight;
var topPoint = topRect.PointToScreen(new Point(0, 0));
var midPoint = midRect.PointToScreen(new Point(0, 0));
var botPoint = botRect.PointToScreen(new Point(0, 0));
TopWin.Dispatcher.Invoke(() => {
TopWin.Left = topPoint.X;
TopWin.Top = topPoint.Y;
TopWin.Width = width;
TopWin.Height = height;
});
MidWin.Dispatcher.Invoke(() => {
MidWin.Left = midPoint.X;
MidWin.Top = midPoint.Y;
MidWin.Width = width;
MidWin.Height = height;
});
BotWin.Dispatcher.Invoke(() => {
BotWin.Left = botPoint.X;
BotWin.Top = botPoint.Y;
BotWin.Width = width;
BotWin.Height = height;
});
return windowBorder.DesiredSize;
}
protected override void OnActivated(EventArgs e) {
TopWin.Dispatcher.Invoke(() => TopWin.Visibility = Visibility.Visible);
MidWin.Dispatcher.Invoke(() => MidWin.Visibility = Visibility.Visible);
BotWin.Dispatcher.Invoke(() => BotWin.Visibility = Visibility.Visible);
//TopWin.Dispatcher.Invoke(TopWin.Show);
//MidWin.Dispatcher.Invoke(MidWin.Show);
//BotWin.Dispatcher.Invoke(BotWin.Show);
//TopWin.Dispatcher.Invoke(() => TopWin.WindowState = WindowState.Normal);
//MidWin.Dispatcher.Invoke(() => MidWin.WindowState = WindowState.Normal);
//BotWin.Dispatcher.Invoke(() => BotWin.WindowState = WindowState.Normal);
//InvalidateArrange();
InvalidateVisual();
}
protected override void OnDeactivated(EventArgs e) {
TopWin.Dispatcher.Invoke(() => TopWin.Visibility = Visibility.Collapsed);
MidWin.Dispatcher.Invoke(() => MidWin.Visibility = Visibility.Collapsed);
BotWin.Dispatcher.Invoke(() => BotWin.Visibility = Visibility.Collapsed);
//TopWin.Dispatcher.Invoke(TopWin.Hide);
//MidWin.Dispatcher.Invoke(MidWin.Hide);
//BotWin.Dispatcher.Invoke(BotWin.Hide);
//TopWin.Dispatcher.Invoke(() => TopWin.WindowState = WindowState.Minimized);
//MidWin.Dispatcher.Invoke(() => MidWin.WindowState = WindowState.Minimized);
//BotWin.Dispatcher.Invoke(() => BotWin.WindowState = WindowState.Minimized);
}
protected override void OnClosed(EventArgs e) {
TopWin.Dispatcher.Invoke(TopWin.Close);
MidWin.Dispatcher.Invoke(MidWin.Close);
BotWin.Dispatcher.Invoke(BotWin.Close);
TopWin.Dispatcher.InvokeShutdown();
MidWin.Dispatcher.InvokeShutdown();
BotWin.Dispatcher.InvokeShutdown();
App.Current.Shutdown();
}
protected override Visual GetVisualChild(int index) => windowBorder;
protected override int VisualChildrenCount => 1;
protected override void OnClosing(CancelEventArgs e) {
titleBar.MouseLeftButtonDown -= handleResize;
titleBar.MouseMove -= move;
}
}
and here's the App.cs
:
class App : Application
{
[STAThread]
static void Main() => new App().Run();
protected override void OnStartup(StartupEventArgs e) {
TopWindow top = null;
MiddleWindow mid = null;
BottomWindow bot = null;
var thread1 = new Thread(() => {
top = new TopWindow() {
Content = new TextBlock() {
Text = "Top Window",
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
FontSize = 36
}
};
Dispatcher.Run();
});
var thread2 = new Thread(() => {
mid = new MiddleWindow() {
Content = new TextBlock() {
Text = "Middle Window",
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
FontSize = 36
}
};
Dispatcher.Run();
});
var thread3 = new Thread(() => {
bot = new BottomWindow() {
Content = new TextBlock() {
Text = "Bottom Window",
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
FontSize = 36
}
};
Dispatcher.Run();
});
thread1.SetApartmentState(ApartmentState.STA);
thread2.SetApartmentState(ApartmentState.STA);
thread3.SetApartmentState(ApartmentState.STA);
thread1.Start();
thread2.Start();
thread3.Start();
App.Current.MainWindow = new RootWindow() {
TopWin = top,
MidWin = mid,
BotWin = bot
};
App.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
App.Current.MainWindow.Show();
}
}
You could download the project from GitHub. How do you solve these issues?