Set button margin with auto window size - c#

I've created a simple custom messagebox that automatically scales depending on the length of the text to be displayed :
public partial class CustomMessageBox : Window
{
public CustomMessageBox(string title, string text)
{
InitializeComponent();
ResizeMode = ResizeMode.NoResize;
label.Content = text;
Title = title;
}
public static void Show(string title, string text)
{
CustomMessageBox box = new CustomMessageBox(title, text);
box.SizeToContent = SizeToContent.WidthAndHeight;
box.ShowDialog();
}
private void button_Click(object sender, RoutedEventArgs e)
{
Close();
}
}
This works nicely however my button is clamping to the bottom side of the window because the window automatically scales :
And the button seems to be moving once the message gets longer :
How would I make sure the button stays centered and have a margin of around 10px from the bottom so it doesn't look that clamped?
I tried to set the Margin manually but that doesn't seem to work.
XAML (largely generated by the designer) :
<Window x:Class="RapidEvent.CustomMessageBox"
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:RapidEvent"
mc:Ignorable="d"
Background="{DynamicResource WindowBackgroundBrush}"
Title="" Height="Auto" Width="Auto">
<Grid>
<StackPanel>
<Label x:Name="label" Content="" HorizontalAlignment="Left" Margin="10,0,0,0" VerticalAlignment="Top" FontSize="13px" RenderTransformOrigin="0.392,0.486"/>
<Button x:Name="button" x:FieldModifier="public" IsDefault="True" Content="_Ok" HorizontalAlignment="Left" Margin="110,40,0,0" VerticalAlignment="Top" Width="80" Height="21" Click="button_Click"/>
</StackPanel>
</Grid>
</Window>

Simply change your StackPanel to a Grid and the HorizonalAlignment of your button to Center and take off all but the bottom margin. You'll also need to set the VerticalAlignment to Bottom. You also need to put the button on row 1.
This way the button will be clamped to the bottom of the dialog and always centred.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label x:Name="label" Content=""
HorizontalAlignment="Left" Margin="10,0,0,0"
VerticalAlignment="Top" FontSize="13px"
RenderTransformOrigin="0.392,0.486"/>
<Button Grid.Row="1" x:Name="button" x:FieldModifier="public"
IsDefault="True" Content="_Ok"
HorizontalAlignment="Center" Margin="0,0,0,20"
VerticalAlignment="Bottom" Width="80" Height="21"/>
</Grid>

Use grid instead of StackPanel:
<Grid >
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<telerik:Label x:Name="label" Content="LSFFD" HorizontalAlignment="Left" Margin="10,0,0,0" VerticalAlignment="Top" FontSize="13px" RenderTransformOrigin="0.392,0.486"/>
<Button Grid.Row="1" x:Name="button" x:FieldModifier="public" Content="_Ok" HorizontalAlignment="Center" Margin="0 0 0 10" VerticalAlignment="Bottom" Width="80" Height="21" Click="button_Click"/>
</Grid>

Related

WPF - Getting position of a control keeps returning {0;0}

I'm trying to get the positions of controls (buttons) but it keeps returning {0;0}. I'm sure there's an explanation for this, but I can't figure out why this happens.
I want the position of the control, relative to the window or a certain container. My buttons are arranged in another grid. Taking the margins of these buttons would just give 0,0 since they're all inside grid cells.
What I tried:
- var point = btnTest.TransformToAncestor(mainGrid).Transform(new Point());
- UIElement container = VisualTreeHelper.GetParent(btnTest) as UIElement;
Point relativeLocation = btnTest.TranslatePoint(new Point(0, 0), mainGrid);
I tried this with a grid as a parent and with a canvas. Everything I try gives me {0,0}. When I change the new Point parameters, the position does change. It stays the same as the parameters.
Small part of my XAML:
<Grid x:Name="mainGrid">
<Grid Name="buttonGrid" Margin="105,64,98.4,97.8">
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<Button x:Name="btnTest" Grid.Row="0" Grid.Column="0" Content="Button" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" Width="26" Height="29"/>
<Button x:Name="btnTest2" Grid.Row="1" Grid.Column="1" Content="Button" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" Width="26" Height="29"/>
</Grid>
</Grid>
Your code works perfectly fine, it is the timing that is the issue. The UI elements must be drawn before the position can be retrieved.
The code sample below shows the point extraction running in the constructor with the result 0,0 and then running in the loaded event which returns the desired result 84,78.
<Window x:Class="WpfApp7.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">
<Grid x:Name="mainGrid">
<Button x:Name="btnTest" Content="TileButton" HorizontalAlignment="Left" Margin="84,78,0,0" VerticalAlignment="Top" Width="109" Height="103"/>
</Grid>
public MainWindow()
{
InitializeComponent();
GetPoint();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
GetPoint();
}
private void GetPoint()
{
var point = btnTest.TransformToAncestor(mainGrid).Transform(new Point());
UIElement container = VisualTreeHelper.GetParent(btnTest) as UIElement;
Point relativeLocation = btnTest.TranslatePoint(new Point(0, 0), mainGrid);
MessageBox.Show($"X = {relativeLocation.X} Y = {relativeLocation.Y}");
}

Position image in Grid with ZIndex

I have an image on top of a button that is on a grid. I want to place the image behind the button when I click on the button "Hide Image". I have tried with Panel.ZIndex, but apparently it is not available for Grid.
<Grid HorizontalAlignment="Left" Height="100" Margin="201,79,0,0" VerticalAlignment="Top" Width="100">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button x:Name="btn_1" Grid.Column="0" Grid.Row="0" Panel.ZIndex="-1"/>
<Image Source="Max_dog.png" Grid.Column="0" Grid.Row="0"/>
<Button x:Name="btn_2" Grid.Column="1" Grid.Row="0"/>
<Button x:Name="btn_3" Grid.Column="0" Grid.Row="1"/>
<Button x:Name="btn_4" Grid.Column="1" Grid.Row="1"/>
</Grid>
<Button Content="Button" Margin="215,205,228.667,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
The right way to do this in WPF is to have a view model that you attach to the data context of the window or a control. Then you bind a property of the view model to the Visibility property of the image.
public class MyViewModel : INotifyPropertyChanged
{
private bool _isImageVisible;
public bool IsImageVisible
{
get { return _isImageVisible; }
set {
if (value != _isImageVisible) {
_isImageVisible = value;
OnPropertyChanged(nameof(ImageVisibility));
}
}
}
public Visibility ImageVisibility => _isImageVisible
? Visibility.Visible
: Visibility.Hidden; // or Collapsed
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
In XAML
<Image Source="Max_dog.png" Grid.Column="0" Grid.Row="0"
Visibility="{Binding ImageVisibility}"/>
Not that you cannot bind the Visibility property to a Boolean. Therefore I made two properties a Boolean property that you can easily set and another one exposing the required Visibility enum.
I found the solution
private void Button_Click(object sender, RoutedEventArgs e)
{
btn_1.SetValue(Panel.ZIndexProperty, 3);
}
WPF forms the controls in the layout on stack. The item lower in the stack will always have lower zIndex compared to item on higher position. The solution here to change the declaration of statements to
<Grid HorizontalAlignment="Left" Height="100" Margin="201,79,0,0" VerticalAlignment="Top" Width="100">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image Source="Max_dog.png" Grid.Column="0" Grid.Row="0"/>
<Button x:Name="btn_1" Grid.Column="0" Grid.Row="0"/>
<Button x:Name="btn_2" Grid.Column="1" Grid.Row="0"/>
<Button x:Name="btn_3" Grid.Column="0" Grid.Row="1"/>
<Button x:Name="btn_4" Grid.Column="1" Grid.Row="1"/>
</Grid>
<Button Content="Button" Margin="215,205,228.667,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
See the declaration of button and image has been reversed.

WPF minimizing window into bottom of parrent window

I try to make a "email messenger". I have two windows. Main window, there is ribbon with bookmarks and one button (New message). This button invoke second window NewMessage. The Mainwindow is owner of the NewMessage window.
MainWindow:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
NewMessage newmessage = new NewMessage();
newmessage.Show();
}
}
}
MainWindow XAML:
<Window x:Class="Messenger.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:Messenger"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Content="New Message" Height="20" Width="80
" HorizontalAlignment="Left" Margin="35,46,0,0" VerticalAlignment="Top" Click="Button_Click" />
<TabControl HorizontalAlignment="Left" Height="254" Margin="34,44,0,0" VerticalAlignment="Top" Width="461" Background="{x:Null}" SelectedIndex="1">
<TabItem Header="Delivered" Visibility="Hidden" Width="80">
<Grid Background="#FFE5E5E5"/>
</TabItem>
<TabItem Header="Delivered" Visibility="Visible" Width="80">
<Grid Background="#FFE5E5E5"/>
</TabItem>
<TabItem Header="Sent" Width="80">
<Grid Background="#FFE5E5E5"/>
</TabItem>
<TabItem Header="Trash" Width="80">
<Grid Background="#FFE5E5E5"/>
</TabItem>
</TabControl>
</Grid>
NewMessage:
public partial class NewMessage : Window
{
public NewMessage()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
}
}
NewMessage XAML:
<Window x:Class="Messenger.NewMessage"
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:Messenger"
mc:Ignorable="d"
Title="NewMessage" Height="351.047" Width="814.398">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*"/>
<ColumnDefinition Width="27*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="23*"/>
<RowDefinition Height="24*"/>
<RowDefinition Height="243*"/>
<RowDefinition Height="31*"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="Komu" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<TextBox Grid.Row="0" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Top" />
<Label Grid.Row="1" Content="Předmět" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<TextBox Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Top" />
<RichTextBox HorizontalAlignment="Left" Height="243" Grid.Row="2" VerticalAlignment="Top" Width="806" Grid.ColumnSpan="2">
<FlowDocument>
<Paragraph>
<Run Text="Sem zadejte text zprávy"/>
</Paragraph>
</FlowDocument>
</RichTextBox>
<Button Grid.Row="3" Content="Odeslat" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Top" Width="75" Margin="0,5,90,0"/>
<Button Grid.Row="3" Content="Storno" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Top" Width="75" Margin="0,5,10,0" Click="Button_Click"/>
</Grid>
I would like to, when I minimize NewMessage window, this window minimize to the bottom of MainWindow "taskbar". If you know gmail, there is the same principle. Any idea?

Scroll to object on Button click (C# /Xaml)

Is there a way to have a xaml page scroll to a particular object on a button click? For example, I have three buttons at the top of my page. I would like each button to move the scrollviewer to the top, middle, and bottom section of the page. How can I make this happen? Thanks!
I try to create the Xaml and to solve the problem. This is my solution.
This is the Xaml code.
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Button HorizontalAlignment="Left" Content="Top" Click="Button_Click" ></Button>
<Button HorizontalAlignment="Center" Content="Center" Click="Button_Click_1" ></Button><Button Content="Botton" HorizontalAlignment="Right" Click="Button_Click_2" ></Button>
<ScrollViewer Grid.Row="1" Name="MyScrollViewer" MaxZoomFactor="9">
<StackPanel>
<TextBlock Name="TextBlock" Height="20"> </TextBlock>
<Rectangle Height="300" Width="100" Fill="BlanchedAlmond"></Rectangle>
<Rectangle Height="300" Width="100" Fill="Blue"></Rectangle>
<Rectangle Height="300" Width="100" Fill="BlueViolet"></Rectangle>
<Rectangle Height="300" Width="100" Fill="Chartreuse"></Rectangle>
<Rectangle Height="300" Width="100" Fill="Crimson"></Rectangle>
</StackPanel>
</ScrollViewer>
</Grid>
And this is the .cs Code
private void Button_Click(object sender, RoutedEventArgs e)
{
MyScrollViewer.ScrollToVerticalOffset(0);
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
var scrollableHeight = MyScrollViewer.ScrollableHeight;
var height= scrollableHeight / 2;
MyScrollViewer.ScrollToVerticalOffset(height);
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
MyScrollViewer.ScrollToVerticalOffset(MaxHeight);
}
}

How to change a grid layout when orientation is changed

I'm creating a win8 app and I need to change the layout of my grid so everything fits on screen when the user flips between orientations. I understand I need to use VisualStateManager but I can't understand any tutorials. If I have this code:
<Grid>
<Button x:Name="button1" Margin="188,73,286,0" VerticalAlignment="Top"/>
<Button x:Name="button2" Margin="236,73,238,0" VerticalAlignment="Top"/>
<Button x:Name="button3" Margin="284,73,190,0" VerticalAlignment="Top"/>
</Grid>
How would I use visual state manager to change the buttons so they are now orientated in a column (one above the other) instead of in a row when the orientation is changed to portrait from landscape?
Thanks
xaml code
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" SizeChanged="Page_SizeChanged_1">
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="FullScreenLandscape">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Content="Button1" HorizontalAlignment="Center" VerticalAlignment="Center"></Button>
<Button Content="Button2" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center"></Button>
<Button Content="Button3" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center"></Button>
</Grid>
<Grid x:Name="Snapped">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Button Content="Button1" HorizontalAlignment="Center" VerticalAlignment="Center"></Button>
<Button Content="Button2" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center"></Button>
<Button Content="Button3" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center"></Button>
</Grid>
</Grid>
C# code
private void Page_SizeChanged_1(object sender, SizeChangedEventArgs e)
{
switch (ApplicationView.Value)
{
case ApplicationViewState.FullScreenLandscape:
VisualStateManager.GoToState(this, "FullScreenLandscape", false);
Snapped.Visibility = Visibility.Collapsed;
break;
case ApplicationViewState.Snapped:
VisualStateManager.GoToState(this, "Snapped", false);
FullScreenLandscape.Visibility = Visibility.Collapsed;
Snapped.Visibility = Visibility.Visible;
break;
default:
return;
}
}
Another Method
xaml code
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="landscape">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox x:Name="t1" Grid.Column="0" FontSize="24" Height="100"/>
<TextBox x:Name="t2" Grid.Column="1" FontSize="24" Height="100"/>
<TextBox x:Name="t3" Grid.Column="2" FontSize="24" Height="100"/>
</Grid>
<Grid x:Name="snap" Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
</Grid>
</Grid>
C# code
private void Page_SizeChanged_1(object sender, SizeChangedEventArgs e)
{
if (Windows.UI.ViewManagement.ApplicationView.Value == Windows.UI.ViewManagement.ApplicationViewState.FullScreenLandscape)
{
landscape.Visibility = Windows.UI.Xaml.Visibility.Visible;
snap.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
t1.SetValue(Grid.ColumnProperty, 0);
t2.SetValue(Grid.ColumnProperty, 1);
if (t1.Parent != landscape)
{
snap.Children.Remove(t1);
snap.Children.Remove(t2);
landscape.Children.Add(t1);
landscape.Children.Add(t2);
}
}
else if(Windows.UI.ViewManagement.ApplicationView.Value == Windows.UI.ViewManagement.ApplicationViewState.Snapped)
{
landscape.Children.Remove(t1);
landscape.Children.Remove(t2);
landscape.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
snap.Visibility = Windows.UI.Xaml.Visibility.Visible;
t1.SetValue(Grid.RowProperty, 0);
t2.SetValue(Grid.RowProperty, 1);
if (t1.Parent != snap)
{
landscape.Children.Remove(t1);
landscape.Children.Remove(t2);
snap.Children.Add(t1);
snap.Children.Add(t2);
}
}
}

Categories