WPF WindowChrome unwanted black shadow - Caused by SizeToContent="WidthAndHeight" - wpf

I'm trying to create a custom popup window in WPF, but I can't seem to do it without a there being a black "drop shadow" around it. I'm using ContentControl for the body of it so that I can change the body for different popups.
I can remove the "shadow" by removing SizeToContent="WidthAndHeight", but then I don't have a window that adapts to it's content.
Here's the xaml
<Window x:Class="PriceFinding.Utility.Dialogs.Service.DialogWindow"
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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PriceFinding.Utility.Dialogs.Service"
mc:Ignorable="d"
SizeToContent="WidthAndHeight"
WindowStartupLocation="CenterScreen"
MinHeight="300" MinWidth="800"
Background="{StaticResource BrushPrimary}"
>
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="50"/>
</WindowChrome.WindowChrome>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" WindowChrome.IsHitTestVisibleInChrome="True" VerticalAlignment="Top" Background="{StaticResource BrushPrimaryDark}" Name="TitleBar" Height="35">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<Image Source = "pf.ico" Height="20" Width="20" Margin="5,0" />
<Label Content="{Binding Title}" VerticalAlignment="Center" HorizontalAlignment="Left" FontSize="14"/>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,5,0">
<Button
x:Name="MinButton"
Height="35" Width="35" Padding="0"
Command="{Binding MinimizeButton.MinimizeCommand}">
</Button>
<Button
x:Name="MaxButton"
Height="35" Width="35" Padding="0"
HorizontalAlignment="Left"
Command="{Binding MaximizeButton.MaximizeCommand}">
</Button>
<Button
x:Name="CloseButton"
Height="35" Width="35" Padding="0"
HorizontalAlignment="Right"
Command="{Binding CloseButton.CloseCommand}">
</Button>
</StackPanel>
</Grid>
<ContentControl Grid.Row="1" x:Name="ContentPresenter" Content="{Binding}"></ContentControl>
</Grid>
How can I get around this?

Here (or here, for the more daring) is a workaround!
This is quite a weird problem, but, indeed, running an event when the content is rendered:
ContentRendered="Window_OnContentRendered"
like so:
private void Window_OnContentRendered(object sender, EventArgs e)
{
InvalidateVisual();
}

InvalidateVisual does not remeasure content of window. Also no need to change the chrome.
This helped me:
protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
// Content of window may be black in case of SizeToContent is set.
// This eliminates the problem.
// Do not use InvalidateVisual because it may implicitly break your markup.
InvalidateMeasure();
}

You can set the GlassFrameThickness to zero:
<WindowChrome GlassFrameThickness="0"
CaptionHeight="0" />
And that should remove the drop shadow effect and it will also allow you to use the CornerRadius effect if you were interested.

This is caused by a bug in WPF.
See https://social.msdn.microsoft.com/Forums/vstudio/en-US/f51ba061-69e2-4c85-b77a-41307423c2bf/sizetocontentheight-windowstylenone-resizemodenoresize-weirdness?forum=wpf
For a workaround, you can refresh the view. InvalidateVisual did not work for me.
You can attach an event handler to the window like so:
Background="{StaticResource BrushPrimary}" Activated="Window_Activated" StateChanged="Window_Activated"
Then, in the code behind:
private void Window_Activated(object sender, EventArgs e)
{
this.SizeToContent = SizeToContent.Manual;
this.SizeToContent = SizeToContent.WidthAndHeight;
}

Related

Grid splitter behavior (Expand top panel when bottom panel closes)

In my window, two panels are separated by grid splitter. Splitter functionality works properly. When bottom panel closes, I want top panel to occupy total screen space (similar to visual studio IDE) however when I close the panel, it leaves the blank space. Code which demonstrates this problem is given below :
XAML
<Window x:Class="WpfApp1.Window1"
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:WpfApp1"
mc:Ignorable="d"
Title="Window1" Height="450" Width="800" WindowState="Maximized">
<Grid x:Name="grid">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel x:Name="panel1" Grid.Row="0" Background="Bisque" Margin="3" Orientation="Vertical">
<Button Height="50" Content="Button 1" Margin="5"/>
<Button Height="50" Content="Button 2" Margin="5"/>
<Button Height="50" Content="Button 3" Margin="5"/>
</StackPanel>
<GridSplitter Grid.Row="1" Height="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ShowsPreview="True" ResizeDirection="Rows"/>
<StackPanel x:Name="panel2" Grid.Row="2" Background="AliceBlue" Margin="3" Orientation="Vertical">
<Button Content="X" HorizontalAlignment="Right" VerticalAlignment="Top" Click="Button_Click"/>
<Button Height="50" Content="Button 4" Margin="5"/>
<Button Height="50" Content="Button 5" Margin="5"/>
<Button Height="50" Content="Button 6" Margin="5"/>
</StackPanel>
</Grid>
</Window>
Code behind
using System.Windows;
namespace WpfApp1
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
grid.Children.Remove(panel2);
}
}
}
Can anyone suggest any approach or solution to achieve my requirement i.e. upon closing bottom panel, top panel occupies all available space?
Thanks
You could start with these heights:
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
...and simply set the Height of the last one to Auto when you remove the StackPanel:
private void Button_Click(object sender, RoutedEventArgs e)
{
grid.Children.Remove(panel2);
grid.RowDefinitions[Grid.GetRow(panel2)].Height = new GridLength(1, GridUnitType.Auto);
}

Button inside a custom skewed window doesn't allways get mouseEnter event

Here is my code:
<Window x:Class="WPFStackOverFlow.SkewWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
AllowsTransparency="True" WindowStyle="None" Background="Transparent"
Title="MainWindow" Height="600" Width="687">
<Border BorderBrush="Green" BorderThickness="2" Background="White" Width="360" Height="360">
<Border.RenderTransform>
<SkewTransform AngleX="-23" AngleY="10"></SkewTransform>
</Border.RenderTransform>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="23" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="X" Width="23" Name="button1" HorizontalAlignment="Right" Click="button1_Click" Height="23" VerticalAlignment="Bottom"/>
<Grid Grid.Row="1">
<Button Height="100" Width="200"></Button>
<TextBlock Text="Some very very long Text" HorizontalAlignment="Center"/>
</Grid>
</Grid>
</Border>
When I move the mouse cursor over the button sometimes it get focus and sometimes it doesn't. How can I make the button inside this custom window to be like a button in a regular window?
I don't think you can apply transformations to windows.
You can apply them to the controls inside windows.
If you need to simulate transformations to windows you can try something similar to what is described in the answer to this question.

xaml window doesnt center

I have a xaml (window) control which contains a grid and inside that grid, two stackpanel. The second stackpanel is set to "collapsed" per visibility. When the form loads and the button on the form is clicked, the xaml window shows up centered by setting WindowStartupLocation="CenterScreen". But when the button on the xaml is clicked to set the second stackpanel's visibility to visible, it doesn't center no more. Can anyone help resolve this issue or tell me on how to fix this?
Update: After looking closely at this, I think it may be because the visibility is set to collapsed? I've tried instead of collapsed, hidden, and it centered it but with the column being shown empty as it's used by the stackpanel.
Here are the codes:
Form1.cs
public Form1()
{
InitializeComponent();
this.StartPosition = FormStartPosition.CenterScreen;
}
private void button_Click(object sender, EventArgs e)
{
MainWindow childWindow = new MainWindow();
childWindow.Show();
}
MainWindw.xaml
<Window x:Class="ChildProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:ChildProject"
Title="MainWindow"
Width="Auto"
Height="Auto"
SizeToContent="WidthAndHeight"
AllowsTransparency="False"
ResizeMode="NoResize"
WindowStyle="None"
WindowStartupLocation="CenterScreen">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<StackPanel x:Name="stkpnlMain"
Grid.Column="0"
Grid.Row="0"
Orientation="Vertical">
<Label Content="This is suppose to display message on right ..."
FontStyle="Italic"
FontWeight="Bold"/>
<Button Content="Click Me"
Width="75"
Margin="5" Click="Button_Click" />
</StackPanel>
<StackPanel x:Name="stkpnlDisplay"
Grid.Column="1"
Grid.Row="0"
Margin="5,0,0,0"
Orientation="Vertical"
Background="YellowGreen" Visibility="Collapsed" >
<Label Content="... First now shows ..."
BorderBrush="Black"
BorderThickness="1"
Background="Yellow" />
<Label Content="Hopefully this will work"
BorderBrush="Red"
BorderThickness="3"
Margin="0,5"
Background="White" />
</StackPanel>
</Grid>
MainWindow.xaml.cs
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
stkpnlDisplay.Visibility = Visibility.Visible;
}

Creating a scrollable WPF usercontrol

For an application that I am working on I want to create a custom control that has several buttons on it, If there are too many buttons I need it to scroll. However, I don't want to use the standard scrollbar instead I just want to have two buttons at either end of the control one to scroll up and the other down. What is the best way to achieve this?
Is it possible to change the style of the scrollbar so that they are just buttons and not the full horizontal GUI?
You would normally use a ScrollViewer to achieve this. For example:
<UserControl x:Class="WpfApplication2.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="200" d:DesignWidth="300">
<ScrollViewer>
<StackPanel>
<Button Content="Test"/>
<Button Content="Test"/>
<Button Content="Test"/>
<Button Content="Test"/>
<Button Content="Test"/>
<Button Content="Test"/>
<Button Content="Test"/>
<Button Content="Test"/>
<Button Content="Test"/>
<Button Content="Test"/>
<Button Content="Test"/>
<Button Content="Test"/>
</StackPanel>
</ScrollViewer>
</UserControl>
Will display a vertical scrollbar automatically when required.
You can change the behaviour by specifying VerticalScrollbarVisibility like this
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ScrollViewer VerticalScrollBarVisibility="Visible">
<ScrollViewer VerticalScrollBarVisibility="Hidden">
<ScrollViewer VerticalScrollBarVisibility="Disabled">
There is of course a HorizontalScrollBarVisibility property as well.
The way to solve a problem like this is to examine the properties and methods of the control.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Width="40" HorizontalAlignment="Left" Content="Up" Click="clickSVup"/>
<ScrollViewer x:Name="svBtn" Grid.Row="1" Width="100" HorizontalAlignment="Left"
VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden">
<StackPanel>
<TextBlock Text="Text 01"/>
<TextBlock Text="Text 02"/>
<TextBlock Text="Text 03"/>
<TextBlock Text="Text 04"/>
<TextBlock Text="Text 05"/>
<TextBlock Text="Text 06"/>
<TextBlock Text="Text 07"/>
<TextBlock Text="Text 08"/>
<TextBlock Text="Text 09"/>
<TextBlock Text="Text 10"/>
<TextBlock Text="Text 11"/>
<TextBlock Text="Text 12"/>
<TextBlock Text="Text 13"/>
<TextBlock Text="Text 14"/>
<TextBlock Text="Text 15"/>
<TextBlock Text="Text 16"/>
<TextBlock Text="Text 17"/>
<TextBlock Text="Text 18"/>
<TextBlock Text="Text 19"/>
</StackPanel>
</ScrollViewer>
<Button Grid.Row="2" Width="40" HorizontalAlignment="Left" Content="Down" Click="clickSVdn"/>
</Grid>
private void clickSVdn(object sender, RoutedEventArgs e)
{
svBtn.PageDown();
}
private void clickSVup(object sender, RoutedEventArgs e)
{
svBtn.PageUp();
}
I would advise you to use the standard windows scrollbar instead using some custom buttons for scroll up and scroll down. The users are very used to it for scrolling purposes. If you use two buttons you have to further display something else like scrolling progress. Don't reinvent the wheel :)

How to use content of derived controls in silverlight

In my project lots of views must have Ok,Cancel button to bottom of view. So i want create a base control. And add Ok, Cancel button to bottom of this control. Then i will inherite this control. In the inherited control i want to ad a textbox to near this buttons. How can i do this?
I believe there is a template for the base control.Is so in the inherited control's template edit the button panel and add textbox.
You can create Control which is inherited from ContentControl and define your buttons in ControlTemplate of it. Then you can just use this control as shown in sample.
ControlWithButtons.cs
[TemplatePart(Name="btnOk", Type= typeof(Button))]
public class ControlWithButtons : ContentControl
{
public ControlWithButtons()
{
this.DefaultStyleKey = typeof(ControlWithButtons);
}
Button _btnOk;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_btnOk = GetTemplateChild("btnOk") as Button;
if (_btnOk != null)
{
// do what you want with you button
_btnOk.Click += new RoutedEventHandler(_btnOk_Click);
}
}
void _btnOk_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Ok button clicked");
}
}
Generic.xaml (must be in (ProjectDir)/Themes/Generic.xaml)
(do not forget xmlns:local="clr-namespace:Test")
<Style TargetType="local:ControlWithButtons">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:ControlWithButtons">
<Border Background="Yellow" CornerRadius="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Border Margin="10" Background="LightGray">
<ContentPresenter/>
</Border>
<Button Grid.Row="1" x:Name="btnOk" Content="OK" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="5"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Using your control:
<Grid x:Name="LayoutRoot" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<local:ControlWithButtons Width="300" Height="250" HorizontalAlignment="Center" VerticalAlignment="Center">
<!-- TextBox is put into control -->
<TextBox Width="200" Height="Auto" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="5" />
<!-- You can also specify ContentTemplate for ControlWithButtons -->
<!-- (see in MSDN "http://msdn.microsoft.com/en-us/library/system.windows.controls.contentcontrol.contenttemplate(v=vs.95).aspx") -->
</local:ControlWithButtons>
</Grid>
I found the solution. [ContentProperty("")] attribute solved my problem.
Like this:
Base Xaml
<Grid Name="layoutRoot" VerticalAlignment="Stretch" >
<Grid.RowDefinitions>
<RowDefinition Height="289*" />
<RowDefinition Height="51" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="1" Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Orientation="Horizontal">
<Button Name="btnOk" Content="Ok" Height="23" Width="75" HorizontalAlignment="Left" Margin="10,10,10,10" Command="{Binding Path=OnApply, Mode=OneWay}"/>
<Button Name="btnCancel" Content="Cancel" Height="23" Width="75" HorizontalAlignment="Left" Margin="10,10,10,10"/>
</StackPanel>
<Grid Name="rootContent" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.Column="0" Grid.Row="0" />
</Grid>
</sdk:ChildWindow>
Base CodeBehind
[ContentProperty("RootContentControl")]//This attribute solved my problem.
public partial class BaseView : ChildWindow
{
public BaseView()
{
InitializeComponent();
}
public UIElementCollection RootContentControl
{
get { return rootContent.Children; }
}
}
Inherited Xaml
<Views:BaseView x:Class="MvvmLight1.Views.InheritedView"
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:Views="clr-namespace:MvvmLight1.Views"
xmlns:viewModels="clr-namespace:MvvmLight1.ViewModel"
mc:Ignorable="d" d:DesignHeight="244" d:DesignWidth="392"
DataContext="{Binding Source=viewModels:InheritedViewModel}">
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch" >
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
</Grid>
</Views:BaseView>
Inherited CodeBehind
public partial class InheritedView : BaseView
{
public InheritedView()
{
InitializeComponent();
}
}

Resources