C# WPF Can't click button after defining margin - c#

I have created a button in my WPF Application using the following code:
Button EditButton = new Button();
EditButton.Margin = new System.Windows.Thickness(Location[0], Location[1], 0, 0);
EditButton.Height = double.Parse("20");
EditButton.Width = double.Parse("20");
EditButton.Cursor = System.Windows.Input.Cursors.Hand;
EditButton.Content = "TEST!";
EditButton.Click += new System.Windows.RoutedEventHandler(Edit_Click);
Grid.Children.Add(EditButton);
Location[1] += 17;
The button works perfectly when I have not defined EditButton.Margin but as soon as I define it I can't click it and the cursor does not change. I have searched the internet around for an answer and none of them seemed to work. Thanks in advance.

If you cannot click the control you have created, then it is generally being caused by other control being on top of it.
I would suggest altering your code slightly and move on from that point:
var stackPanel = new StackPanel();
var button = new Button();
button.Content = "Your Button";
button.Click += new System.Windows.RoutedEventHandler(Edit_Click);
stackpanel.Children.Add(button);
I suggest using StackPanel as it automatically arrange your control and thus prevents it from overlapping you can start from this point on see whether issue was caused by grid or some other component.
Button will stretch by default to its content, so will StackPanel.

Not sure what 'Location' is in your code, and I assume 'Grid' is the name of the grid. The below works.
public MainWindow()
{
InitializeComponent();
Button EditButton = new Button();
EditButton.Margin = new System.Windows.Thickness(10, 10, 0, 0);
EditButton.Height = double.Parse("20");
EditButton.Width = double.Parse("20");
EditButton.Cursor = System.Windows.Input.Cursors.Hand;
EditButton.Content = "TEST!";
EditButton.Click += new System.Windows.RoutedEventHandler(Edit_Click);
Grid.Children.Add(EditButton);
// Location[1] += 17;
}
private void Edit_Click(object sender, RoutedEventArgs e)
{
throw new NotImplementedException();
}
XAML -
<Window x:Class="WpfApplication6.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="Grid">
</Grid>
</Window>

It looks like you want to do this programmatically, but if you define it in XAML, you could set the button's Panel.ZIndex property to some high number to bring it to the front:
<Button Content="TEST!" Panel.ZIndex="1000" Height="20" Width="20" Cursor="Hand" Click="Edit_Click" />
Hope that helps somebody...

Related

How to recenter UserControl(s) in Window

We have BaseDialogView with next xaml code:
<Window x:Class="Test.BaseDialogView"
Height="475"
WindowStartupLocation="CenterOwner"
SizeToContent="Height"
ResizeMode="CanResize"
SizeChanged="Window_SizeChanged">
<ContentControl Content="{Binding ContentPage}" />
</Window>
BaseDialogViewModel class:
public class BaseDialogViewModel : AbstractNotifyPropertyChangedItem
{
private UserControl contentPage;
public UserControl ContentPage
{
get { return this.contentPage; }
set
{
if (this.contentPage != value)
{
this.contentPage = value;
this.RaisePropertyChanged(() => this.ContentPage);
}
}
}
}
The usage is very simple:
BaseDialog dialog = new BaseDialog();
BaseDialogViewModel dialogVm = new BaseDialogViewModel();
dialog.Owner = Application.Current.MainWindow;
dialog.DataContext = dialogVm ;
dialogVm.ContentPage = new ActivationView();
dialogVm.ContentPage.DataContext = new ActivationViewModel();
So basically once you have an instance of BaseDialog, you just set ContentControl (by setting dialog.ContentPage and dialog.ContentPage.DataContext).
ActivationView is very simple. For example:
<UserControl x:Class="Test.ActivationView" d:DesignHeight="400" d:DesignWidth="700" MaxWidth="700">
<Grid> .... what ever you need
</UserControl>
The problem is that different UserControls windows are set, which have different width and height. When the first UserControl is shown it's place in the center of the MainWindow, which is ok. Then each new userControl is shown, but it's not centered. How do I center the BaseDialog window for each usercontrol?
I tried this (BaseDialogView):
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
Window w = sender as Window;
this.Top = (Application.Current.MainWindow.Height - w.ActualHeight) / 2;
}
but does not work ok (Some usercontrols are still not pixel centered). I also tried adding this to BaseDialogView Xaml
<Window .... VerticalAlignment="Center">
but it seems to be working only for initial instance.
First of you should really consider propperly implementing the MVVM pattern.
It will make your live easier, also instead of centering the element manually in the size change event you should set its owner and WindowStartupLocation by using
Window win = new Window();
win.Content = new MyUserControl();
win.Owner = this;
win.WindowStartupLocation = WindowStartupLocation.CenterOwner;
Instead of having one window where you keep changing the content i would consider having different windows..but that may vary on your specific case

How do I position a window in WPF in an exact location?

I'm trying to display a window that aligns with an existing component. In this example I want to align it to a button. When i click the button I would like the window to position itself so that it's bottom is just above the button, and it's width is the same as the button. The left of the window should be the same as the left of the button.
To achieve this I use the following xaml:
<Window x:Class="WindowPositioningTest.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:WindowPositioningTest"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Name="MyButton" Content="Click me to see window!" Width="300" Height="50" Click="Button_Click"/>
</Grid>
The onclick function looks like this:
private void Button_Click(object sender, RoutedEventArgs e)
{
var window = new Window();
var myButtonLocation = MyButton.PointToScreen(new Point(0, 0));
window.Width = MyButton.ActualWidth;
window.Height = 300;
window.Left = myButtonLocation.X;
window.Top = myButtonLocation.Y - window.Height;
window.Show();
}
When I click the button a window is displayed like in the picture below.
My question is: why is the window not as wide as the button and why is it not in the right position? It's almost as if there's an invisible frame around the window.
Try this:
private void Button_Click(object sender, RoutedEventArgs e)
{
var window = new Window();
var myButtonLocation = MyButton.PointToScreen(new Point(0, 0));
window.Width = MyButton.ActualWidth + 16;
window.Height = 300;
window.Left = myButtonLocation.X - 8;
window.Top = myButtonLocation.Y - window.Height;
window.Show();
}
It happens beacuse of window border. As you know, window is a composite element. I think when you set Width, you set a width of the working space, not the width of the whole window.

WPF - duplicating a stackpanel

i have this (a rough e.g):
<StackPanel>
<StackPanel Orientation="Horizontal">
<Label .../>
<TextBox .../>
<Button Content="Add new input row" ... />
</StackPanel>
</StackPanel>
pretty self explanatory, i want to add a new Horizontal StackPanel with every click on the button..
is that possible?
thank you!
For this XAML above I will do like this:
In the click event handle of every button name "Add new input row", I mean you can use this event for all of buttons.
private void btn_Click(object sender, RoutedEventArgs e)
{
Button btn = sender as Button;
StackPanel stkButtonParent = btn.Parent as StackPanel;
StackPanel stkCover = stkButtonParent.Parent as StackPanel;
StackPanel newRow = NewRow();
stkCover.Children.Add(newRow);
}
private StackPanel NewRow() {
StackPanel stk = new StackPanel();
stk.Orientation = Orientation.Horizontal;
Label lbl = new Label();
lbl.Foreground = Brushes.Red; // some attribute
TextBox txt = new TextBox();
txt.Background = Brushes.Transparent; // some attribute
Button btn = new Button();
btn.Content = "Add new row";
btn.Click += btn_Click;
stk.Children.Add(lbl);
stk.Children.Add(txt);
stk.Children.Add(btn);
return stk;
}
Yes it is possible try handling the event like this for example:
// Create your StackPanel.
StackPanel sp = new StackPanel();
sp.Orientation = Orientation.Horizontal;
// Add controls to new StackPanel
// Control con = new Control();
// sp.Children.Add(con);
// Add created control to a previously created (and named) container.
myStackPanel.Children.Add(sp);
If you would like your StackPanel to contain some controls you can also add them to it here.
There is a way to do this via XamlReader as well, but I have never tried it.
Here is a link to a short article:
arcanecode.com

WPF Fire event for dynamically added control in stack panel

I am adding adding a radio button to stack panel for each item in List and that happens without issue. (it adds 4 or 6 radio buttons as those would be count of items in my list).
foreach (var nearestgage in nearestgages)
{
StackPanel.Children.Add(new RadioButton { Content = nearestgage.GageSize.ToString(), Margin = new Thickness(1, 1, 1, 1) });
}
Now what i want to do is when any of these dynamically created radio buttons are selected at run time.
I want to fire a event.
So what i am thinking is i will have to attach a handler to my radio button click . I tried a few methods but not able to that. I have another radio button in the grid which does not belong to this group as well. Please suggest what would be the ideal way to do this.
Here's a little sample, adding the event to the radio button when it's generated.
XAML:
<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="350" Width="525"
Loaded="Window_Loaded">
<StackPanel Name="StackPanel">
</StackPanel>
</Window>
C#
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
for (int i = 1; i <= 10; i++)
{
RadioButton rb = new RadioButton();
rb.Content = "Item " + i.ToString();
rb.Click += rb_Click;
StackPanel.Children.Add(rb);
}
}
void rb_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show((sender as RadioButton).Content.ToString());
}
}
To deal with keeping the radio button actions separate, set the group name:
rb.GroupName = "Dynamic";

A tooltip or something similar move with cursor in WPF

Is it possible to move a Tooltip or something like that with cursor when mouse goes on a specific control?
I tried TextBlock, but Margin property not work.
private TextBlock tooltip = new TextBlock();
private void imgRoom_MouseEnter(object sender, MouseEventArgs e)
{
Point position = e.GetPosition((IInputElement)sender);
tooltip.Visibility = System.Windows.Visibility.Visible;
tooltip.Margin = new Thickness(position.X, position.Y, 0, 0);
tooltip.Width = 100;
tooltip.Height = 100;
tooltip.Background = new SolidColorBrush(Colors.Red);
}
private void imgRoom_MouseMove(object sender, MouseEventArgs e)
{
Point position = e.GetPosition((IInputElement)sender);
tooltip.Margin = new Thickness(position.X, position.Y, 0, 0);
}
You can achieve the effect using a Popup and some simple properties upon it. From window code...
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Rectangle Name="rect" Margin="50,50,0,0" Width="100" Height="100" Fill="LightBlue" MouseMove="Rectangle_MouseMove" MouseLeave="Rectangle_MouseLeave" />
<Popup Name="floatingTip" AllowsTransparency="True" Placement="Relative" PlacementTarget="{Binding ElementName=rect}">
<TextBlock>Look At Me</TextBlock>
</Popup>
</Grid>
</Window>
And this is what the codebehind would look like.
...
private void Rectangle_MouseMove(object sender, MouseEventArgs e)
{
if (!floatingTip.IsOpen) { floatingTip.IsOpen = true; }
Point currentPos = e.GetPosition(rect);
// The + 20 part is so your mouse pointer doesn't overlap.
floatingTip.HorizontalOffset = currentPos.X + 20;
floatingTip.VerticalOffset = currentPos.Y;
}
private void Rectangle_MouseLeave(object sender, MouseEventArgs e)
{
floatingTip.IsOpen = false;
}
...
So from the XAML you can see that the popup placement is relative to the rectangle. When you go mousing over the rectangle, it becomes visible, and its position is updated as the mouse moves. Naturally this is a very basic solution, but with some minor tweaks, handling events like 'MouseEnter' and property adjustment you can come up with some really neat effects.
I don't know if this is a best practice, or if it performs well, but you could use an Adorner.
I've created a proof of concept before, but haven't used it in a production scenario (yet). The adorner can be used to create something like this (tooltip), or a custom mouse cursor or drop target icons.
Make sure you set IsHitTestVisible = false if the adorner doesn't need to be hit tested and might appear directly under the mouse location.
UPDATE
Just fully read the description of adorners:
Common applications for adorners include:
Adding functional handles to a UIElement that enable a user to manipulate the element in some way (resize, rotate, reposition, etc.).
Provide visual feedback to indicate various states, or in response to various events.
Overlay visual decorations on a UIElement.
Visually mask or override part or all of a UIElement.
This moves the tooltip around with the mouse cursor.
private void OnMouseMoveHandler(object sender, MouseEventArgs args)
{
if ((sender as FrameworkElement).ToolTip == null)
(sender as FrameworkElement).ToolTip = new ToolTip() { Placement = PlacementMode.Relative };
double x = args.GetPosition((sender as FrameworkElement)).X;
double y = args.GetPosition((sender as FrameworkElement)).Y;
var tip = ((sender as FrameworkElement).ToolTip as ToolTip);
tip.Content = tooltip_text;
tip.HorizontalOffset = x + 10;
tip.VerticalOffset = y + 10;
}

Categories