Drawing in a button_click event makes the button disappears? - wpf

I'm still new in WPF and still facing some problems in working with it. I want to draw some circles when I click a button. I put the instructions for drawing this circle in the method of button_click which means the circles should be drawn when I click the button. The circles are drawn correctly but all the buttons and tools I placed in the form disappear. I suppose this occurs because I'm drawing in the grid where the button is placed. So is there a way to draw the circles inside a certain border or something without anything disappears?
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="449" Width="677">
<Grid Height="297" Width="460">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="181*" />
<ColumnDefinition Width="279*" />
</Grid.ColumnDefinitions>
<Button Content="Button" Height="31" HorizontalAlignment="Left" Margin="185,-53,0,0" Name="button1" VerticalAlignment="Top" Width="94" Click="button1_Click" Grid.Column="1" />
</Grid>

Related

WindowChrome button not hit-test visible when disabled

In WPF you can customize the caption bar using WindowChrome. Adding buttons in the non-client area is fairly simple as long as you remember to set WindowChrome.IsHitTestVisibleInChrome="True".
Now, there is a bug or unexpected/weird behavior when a disabled button is double-clicked. Nothing should happen, but instead the app is maximized.
Steps to reproduce
Create a new WPF project. Preferably targeting .NET 6.
Paste the code below in MainWindow.xaml.
Run the app and double-click the button.
Expected: Nothing happens
Actual: The app is maximized
<Window x:Class="WpfChromeTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" WindowStyle="None" Height="450" Width="800">
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="20" />
</WindowChrome.WindowChrome>
<Window.Template>
<ControlTemplate TargetType="{x:Type Window}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="32" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Width="200" Height="28" VerticalAlignment="Top"
Content="I'm disabled! DOUBLE-CLICK ME!"
WindowChrome.IsHitTestVisibleInChrome="True"
IsEnabled="False" />
</Grid>
</ControlTemplate>
</Window.Template>
</Window>
What am I missing here? Is it a bug? And if so, is there a workaround?
Update
The accepted answer got it right. The reason why it works can be seen in WindowChromeWorker.cs(670) where the call to UIElement.InputHitTest will indeed skip any disabled element. However, on line 673 we find the magic that allows for the suggested solution:
When the parent element has WindowChrome.IsHitTestVisibleInChrome set to true, the callback will correctly return HTCLIENT, effectively swallowing our double click.
In the provided sample, we could simply replace <Grid> with the following, to get the desired behavior:
<Grid WindowChrome.IsHitTestVisibleInChrome="True">
Double clicking on the title bar causes the window to change its state,
when the button is enabled, the double click will be handled by the button and not passed to the title bar.
when the button is disabled, the double click will be passed to the title bar, this will happen if you replace the button with any disabled UIElement.
So the current behavior is normal.
Is there a workaround?
Yes, If you want to disable WindowState change regardless of the button's IsEnabled value, wrap <Button/> with another UI element that will prevent the double click from being passed to the window's title bar if the button is disabled.
<ContentControl
Grid.Row="0"
Width="200"
Height="28"
VerticalAlignment="Top"
WindowChrome.IsHitTestVisibleInChrome="True">
<Button
x:Name="MyButton"
Content="I'm disabled! DOUBLE-CLICK ME!"
IsEnabled="False" />
</ContentControl>

How can we show UWP user control on vertical-top edge of the parent window?

Following XAML in this Microsoft tutorial is showing too much gap between the top edge of the parent window and the UWP user control. Question: How can we make the user control align to the top edge of parent window? Remark: The VerticalAlignment="Top" in the StackPanel below does not help. This question is something similar to this post but in a different context.
<UserControl
x:Class="ClassLibUWP_inside_WPF.MyUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ClassLibUWP_inside_WPF"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:winui="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d"
d:DesignWidth="400" Height="329">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="211*"/>
<ColumnDefinition Width="189*"/>
</Grid.ColumnDefinitions>
<StackPanel Background="LightCoral" Grid.ColumnSpan="2">
<TextBlock>This is a simple custom UWP control</TextBlock>
<Rectangle Fill="Blue" Height="93" Width="100"/>
<TextBlock Text="{x:Bind XamlIslandMessage}" FontSize="50"></TextBlock>
<winui:RatingControl Height="32" />
</StackPanel>
</Grid>
</UserControl>
When you run the app built in the above tutorial, you get the following screen showing the above UWP user control:
I would instead like to display it as follows [notice about no gap between window title and the red stack panel]:
The UserControl has a fixed height that is smaller than the height of the window and thus is vertically centered in the window. Setting VerticalAlignment="Top" on the WindowsXamlHost should give what you want.

Opening new UserControl in MainWindow erases all empty rows

Once I run the program, it opens a UserControl in my MainWindow. The UserControl is a Menu consisting of 3 buttons.
Image of the UserControl:
Menu
The code behind Main Window:
<Window
...
Title="MainWindow" Height="350" Width="525" SizeToContent="WidthAndHeight" >
<Window.DataContext>
<ViewModels:MainWindowViewModel />
</Window.DataContext>
<ContentControl Content="{Binding CurrentViewModel}"/> //Inserts a UserControl
The code behind Menu UserControl:
<UserControl
...
d:DesignHeight="90" d:DesignWidth="525" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100*"/> //Problem
<RowDefinition Height="100*"/>
<RowDefinition Height="100*"/> //Problem
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Grid.Row="1" Margin="30,0" Content="First" Command="{Binding DataContext.SwitchToNextUserControl,
RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}, Mode=OneWay}" />
<Button Grid.Row="1" Grid.Column="1" Margin="30,0" Content="Second"/>
<Button Grid.Row="1" Grid.Column="2" Margin="30,0" Content="Third"/>
</Grid>
THE PROBLEM:
Once the menu is opened, the empty rows (those without buttons, first and third) get collapsed (or just height to 0?), as shown: Running program
I can get over it with setting MinHeight for every row, but it works only on pixels. I'd like them to work in the method of stars ("*"). I guess I could set their height from code behind (using stars), but just the thought of it makes me feel like I rub my right ear with left hand.
Also, once I click on the "First" button, some other UserControl is opened in the window, instead of the "Menu" one, and its rows are also collapsed. Just mentioning it.
So the question is, what should I do to make my UserControls appear just as they look in designer?
You should remove to SizeToContent="WidthAndHeight" from your window XAML.
This causes the height of the window to shrink to fit the size of the UserControl (and effectively the height of the middle Button).

Simple WPF 'panel' issue

a 'simple' about controls layout in wpf. There is a custom control with a grid in wich there is 'panel' on this panel there are three elements two buttons and slider between them. Right button must be anchored to right side of the 'panel', left button to the left side of 'panel' and the slider must FILL ALL THE FREE SPACE BETWEEN buttons. The width(and height) of buttons and grid will be set dinamycaly in the code after. The question is - what kind of 'panel'I must use and how to make it to operate with given task? (stack, dock - have no such functionality even with this "horizontal stratching")
In WinForms - there are no problem width of slider = widthOfGrid - (widtOfBothButtons)
Is this possible to do it in wpf? Or I must compose the code like above in some constructor-like functions?
(offtop- As for me this is a typical task for wpf control and I am surprized that it has too little automatic to solve it)
the code:
<UserControl x:Class="WpfApplication1.UserControl2"
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="42" d:DesignWidth="291">
<Grid x:Name="gridCtrl">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="clnmLbl" Width="Auto"/>
<ColumnDefinition x:Name="clnmPnl" />
</Grid.ColumnDefinitions>
<Label x:Name="lblText" Grid.Column="0" Content="" VerticalAlignment="Center">
</Label>
<DockPanel x:Name="pnlDock" Grid.Column="1">
<Button x:Name="btnLeft" HorizontalAlignment="Left" DockPanel.Dock="Left">
</Button>
<Border x:Name="BorderOfSlider" BorderBrush="#FF000000" BorderThickness="3,3,3,3" CornerRadius="8,8,8,8" >
<Slider x:Name="sldSlider" HorizontalAlignment="Stretch" VerticalAlignment="Center" >
</Slider>
</Border>
<Button x:Name="btnRight" HorizontalAlignment="Right" DockPanel.Dock="Right">
</Button>
</DockPanel>
</Grid>
</UserControl>
That sounds exactly like what a DockPanel does.... it will Dock controls to the sides of the panel, and by default the last control added will stretch and fill all remaining space
<DockPanel>
<Button DockPanel.Dock="Left" Content="Left Button" />
<Button DockPanel.Dock="Right" Content="Right Button" />
<Slider />
</DockPanel>
Also if you're new to WPF, I'd recommend taking a look at this site for a quick visual view of WPF's layout controls.
Edit
Make sure your control that fills all remaining space is the last item added to your DockPanel. If not, it will use a default value of DockPanel.Dock="Left"
There are several ways to do it:
1) DockPanel. Left button will occupy some place at the left side of DockPanel, right button will occupy required space on the right side of remaining space. The rest will be used to display Slider.
<DockPanel>
<Button DockPanel.Dock="Left">Left button</Button>
<Button DockPanel.Dock="Right">Right button</Button>
<Slider />
</DockPanel>
2) Grid. Create grid with 3 columns. Left and right columns will take only required space, the rest will be given to the center column.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0">Left button</Button>
<Slider Grid.Column="1" />
<Button Grid.Column="2">Right button</Button>
</Grid>

Turning the background to gray scale in wpf

Consider a window with loads of multi colored controls on it. I want to put a panel on top of this when some trigger happens in the form such that all the controls looses its color (everything appears in gray scale) except the panel which has just popped up. Can somebody help me with this ??
I would use the Effect property of whatever the client area you wish to gray scale. You will however need to create your own pixel shader to do the gray scale conversion.
http://windowsclient.net/wpf/wpf35/wpf-35sp1-more-effects.aspx
You could quickly test your concept by using the BlurEffect class instead of a custom shader.
<Window x:Class="WpfGrayscaleSample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="327" Width="526">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="239*" />
<RowDefinition Height="50*" />
</Grid.RowDefinitions>
<Canvas Name="clientArea" Background="Transparent" Grid.Row="0">
<!-- Just some controls -->
<Button Height="31" Name="button1" Width="80" Canvas.Left="30" Canvas.Top="125">Button</Button>
<Button Height="28" Name="button2" VerticalAlignment="Bottom" Click="button2_Click" HorizontalAlignment="Right" Width="75" Margin="0,0,16,34" Canvas.Left="66" Canvas.Top="54">Button</Button>
<Rectangle Margin="86,43,0,0" Name="rectangle1" Stroke="Black" Fill="Crimson" Height="59" HorizontalAlignment="Left" VerticalAlignment="Top" Width="109" Canvas.Left="145" Canvas.Top="44" />
</Canvas>
<!-- Button to activate the shader effect -->
<Button Height="23" Margin="15,0,0,21" Name="button3" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="75" Grid.Row="1" Click="button3_Click">Button</Button>
</Grid>
And the event handler for button3 would simply be
private void button3_Click(object sender, RoutedEventArgs e)
{
clientArea.Effect = new BlurEffect() { Radius = 10.0 };
}
Of course it is a bit more work to hook up the custom shader for the gray scaling, but the added bonus of the pixel shader is going to be performance.
In your top-level container (Grid, etc.), just create a Rectangle in a lower ZIndex (or create one more level of nesting).
When you pop your panel up, swap the ZIndex for the Rectangle to fit between your controls and your panel.
As far as the grayscale, there's probably some nifty ways to do it with a VisualBrush, but I think you could get pretty far with a semi-opaque SolidColorBrush on the Rectangle.

Resources