WPF Slow window resizing with borderless window - c#

I have a borderless transparent (rounded corners) WPF Window. It is a fairly complex app with a lot of dialogs that can be shown or hidden. We do this via MVVM binding to the Visibility property using the BooleanToVisibilityConverter which, as far as I am aware, set the visibility to Visible or Collapsed accordingly.
When I resize the window I get a significant lag in the drawing of the window that tends to leave content (borders, framework elements) behind (in that they dont follow the resize very fast). So to clarify I have the main window and the content inside of it (the content is inside a border). The main window will follow the mouse on resize accurately but the content will follow very slowly and will jerk.
I can't figure out what it is, can anyone offer any assistance? Obviously I am assuming that Collapsed dialogs are not resized (or relocated) when the window resizes.
Here is a little example of how we setup a dialog within the Main Window
<Grid x:Name="GlobalModalBackground" Visibility="{Binding ShowGlobalModalBackground, Converter={StaticResource BoolToVisibilityConverter}, FallbackValue=hidden}" Grid.ColumnSpan="2">
<Border CornerRadius="3" Background="#66000000" Opacity="{Binding ModalOpacity}" />
<Grid>
<local:About x:Name="AboutDialog" DataContext="{Binding AboutViewModel}" HorizontalAlignment="Center" VerticalAlignment="Center" Height="300" Width="500"/>
<!-- Other dialogs here -->
In this case, the AboutDialog itself will take care of showing itself or closing itself based on what its ViewModel is set to.

Related

Is it possible to keep the normal buttons when customizing the window chrome?

I'm trying to add a couple of things (a logo on the left and tab control items in the center) to a window chrome using the WindowChrome class. I'd like to keep the normal Win10 buttons, however, just like Google Chrome and similar applications do. Does anyone have any suggestions?
By default, WindowChrome does not hide the caption buttons, but it expands the client area to the entire window frame, so you need to make sure that there's nothing drawn on top of these buttons, such as the window's own background. This could be achieved by setting the background brush to {x:Null}, and also expanding the "glass" to the entire frame by setting it to -1 in order to avoid black (non-drawn) areas behind your controls.
You should also set WindowChrome.IsHitTestVisibleInChrome to True for the tab items (or any control in the non-client area) to make them interactive.
Here's an example:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="200"
Background="{x:Null}">
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="-1" />
</WindowChrome.WindowChrome>
<TabControl Margin="{x:Static SystemParameters.WindowResizeBorderThickness}">
<TabItem WindowChrome.IsHitTestVisibleInChrome="True"
Height="{x:Static SystemParameters.WindowCaptionHeight}"
Header="TabItem" />
</TabControl>
</Window>
And here's what you'll get:

ScrollViewer scrollbars not appearing

I'm working on updating previously working app. Testing shows the ScrollViewer acting oddly when the Zoom makes part of the contained images fall off the screen. The original app was created with VS 2013 as a Universal Windows app. The new app is created with VS 2015 as a Universal Windows app though the target build has been shifted to the anniversary release.
My XAML is defined so:
<ScrollViewer x:Name="SV1" Grid.Row="1" HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
SizeChanged="SV1_SizeChanged" ZoomMode="Enabled" >
<StackPanel x:Name="ImagePanel" Orientation="Horizontal" HorizontalAlignment="Center"
VerticalAlignment="Top" >
<Image x:Name="ImageLeft" Stretch="Uniform" />
<Image x:Name="ImageRight" Stretch="Uniform" />
</StackPanel>
</ScrollViewer>
The user can change the ZoomLevel of the ScrollViewer. The zoom change is implemented using SV1.ChangeView(null, null, zoomFactor).
The images visibly change size on the screen, but as they fall off the right or bottom the scrollbars don't appear. Even changing the visibility properties to "Visible" instead of "Auto" doesn't cause the scrollbars to appear. When the size changes and for a brief instant a thin line will appear where the bars should be and then disappear. Additionally, user input that would normally scroll like moving the mouse wheel does nothing.
Based on other commentary, I've tried replacing the StackPanel with a Grid with no apparent effect.
I'm drawing a blank. Any ideas?
It appears the answer is the next control which shares the same visual space needs to be set to Visibility="Collapsed" in the XAML. The visibility is controlled programmatically, but without the XAML tag the scrollbars of the previous control don't appear and with the tag they do.

WPF Popup's alignment point inconsistent (top right, or top left) with Placement=AbsolutePoint

I am seeing inconsistent placement of my Popup control when my application is run on different computers. I have the Placement set to AbsolutePoint and experience the popup being aligned to popup's top right on 2 computers, but to the popup's top left on 1 other computer (when running the same application on each computer).
I am positioning the popup using the HorizontalOffset and VerticalOffset dependency properties, relative to the screen's top left coordinate.
The documentation (https://msdn.microsoft.com/en-us/library/bb613596%28v=vs.110%29.aspx) shows that the popup alignment point should be to the top left of the popup, with the target area being the whole screen (and so target origin in the top left of the screen).
Thinking that it might be a change in the .Net framework or a difference in display scaling factors (unlikely, but still), I gathered the following info, but I cannot see an obvious reason for this behaviour;
The computers where the popup alignment point is to the popup's top right are:
1).Net Framework 4.5.1 and scaling factor of 125%
2).Net Framework 4.5.2 and scaling factor of 100%
The computer where the popup alignment point is to the popup's top left is:
1).Net Framework 4.5.2 with an unknown scaling factor (I need access to it to check again).
Any ideas why the placement is inconsistent? It is not to do with the screen's boundaries - the popup is not near any edge.
I fixed this issue by adding a border in the same grid col/row as the desired placement target. Then set this as the placement target instead. By binding the width of this border to the popup content it will adjust it's width automatically therefore the alignment (left or right) is irrelevant. If you want to still control alignment, you can do that by aligning the placement target border. Hope that makes sense, if not, here is a quick example.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Popup x:Name="StartMenuPopup" Placement="Top" PlacementTarget="{Binding ElementName=PopupTarget}" >
<Border x:Name="PopupBorder">
</Border>
</Popup>
<Border x:Name="PopupTarget" Grid.Row="1" Width="{Binding ActualWidth, Mode=OneWay, ElementName=PopupBorder}"
BorderThickness="0" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<startmenu:TaskBar Grid.Row="1">
<startmenu:TaskBar.StartButton>
<startmenu:ToggleMenu Width="36" x:Name="StartButton"
ImageData="{Binding StartButtonImageData}"
AssociatedPopup="{Binding ElementName=StartMenuPopup}"
IsOpen="{Binding StartMenuOpen, Mode=TwoWay}"/>
</startmenu:TaskBar.StartButton>
</startmenu:TaskBar>
</Grid>
The popup PlacementTarget binds to the PopupTarget border, and the PopupTarget border width binds back to the PopupBorder element. This makes the PopupTarget border the same width as the popup therefore negating the alignment issue.

ElementFlow element disables controls

I am using the Fluidkit ElementFlow control that I use to display a UserControl that contains textblock with a ScrollViewer as well as button and when they are displayed in the ElementFlow control, all of the buttons and the ScrollViewer seem to be disabled because I can't scroll the ScrollViewer scrollbar and even a simple action as hovering over a button doesn't do anything to the button.
Below is an example of the TextBlock in a ScrollViewer that does not allow for scrolling when used in the ElementFlow.
How can this be fixed?
<ScrollViewer
Height="1200" Width="800"
MaxHeight="1200" MaxWidth="800"
VerticalScrollBarVisibility="Auto">
<TextBlock
Height="Auto" Width="800"
MaxWidth="800"
FontSize="20"
Text="Super long text"
TextWrapping="Wrap"/>
</ScrollViewer>
Just looking over the source code for the project, it looks like it is creating a 3D mesh, and painting the controls on the mesh. This would prevent all user interaction. I don't think there is an easy way to work around this.
However, since you have the source code, you can do the work yourself to make it happen. You're going to need to modify how the ElementFlow represents its items. Look at the CreateMeshModel function. It is currently creating a mesh and applying a VisualBrush to it. Instead, look at the blog post Interacting with 2D on 3D in WPF to figure out what needs to happen.

Make Background Black Except for Single Control

I have this:
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<StackPanel Orientation="Horizontal">
<StackPanel Width="100" Margin="20">
<CheckBox x:Name="cbFoo1" Content="Foo"/>
<TextBlock Text="Foo"/>
<TextBox />
</StackPanel>
<StackPanel Width="100" Margin="20">
<CheckBox x:Name="cbFoo2" Content="Foo"/>
<TextBlock Text="Foo"/>
<TextBox />
</StackPanel>
</StackPanel>
<Rectangle Fill="#BF000000" x:Name="rOverlay"/>
</Grid>
</Window>
I want to make a function foo with argument argControls() that makes rOverlay cover every control in the window except argControls(). Does anyone have any idea how to do this?
What about setting the visibility of the control to Collapsed when you want to hide them.
Option 1 - Draw Order
While a bit of a hack, perhaps the simplest way to accomplish this is to place controls that you wish covered before the rectangle and controls that you wish visible after the rectangle.
One step better (and not a hack) would to use the Panel.ZIndex property instead. This allows you to control the order that the UI elements are drawn regardless of the order that they are defined. This would be accomplished by setting the Panel.ZIndex as follows:
rOverlay to some arbitrary value (like 1)
controls to be covered to something lower than rOverlay (like 0)
controls to be visible to something higher than rOverlay (like 2)
It should however be noted that any transparent regions of your controls will still display the black rectangle behind them. This can either be specifying a background colour or by using another option presented here.
Option 2 - Clipping
Another more complex method involves setting the Clip property of the rectangle to a geometry that only includes the regions that you wish filled. This would likely be accomplished by using an instance of CombinedGeometry class with the CombineMode of Exclude. This would prevent the rectangle from drawing anything over regions outside the clipped region.

Categories