When I add Popup to my XAML like this
<Grid>
...other controls
<Popup x:Name="popup" Width="200" Height="200" >
</Popup>
</Grid>
It behaves as though the popup is there even though I did not toggle IsOpen = true (but the space is blank so no popup is visible)
However when I do the same from the code behind (add a popup) like this, it works like it should, it doesn't interfere with any controls (i.e. shift them) and it pops up as expected over top the other controls.
Popup p = new Popup();
// Create some content to show in the popup. Typically you would
// create a user control.
Border border = new Border();
border.BorderBrush = new SolidColorBrush(Colors.Black);
border.BorderThickness = new Thickness(0);
StackPanel panel1 = new StackPanel();
panel1.Background = new SolidColorBrush(Colors.);
Button button1 = new Button();
button1.Content = "Close";
button1.Margin = new Thickness(5.0);
button1.Click += new RoutedEventHandler(Feedback_Click);
TextBlock textblock1 = new TextBlock();
textblock1.Text = "The popup control";
textblock1.Margin = new Thickness(5.0);
panel1.Children.Add(textblock1);
panel1.Children.Add(button1);
border.Child = panel1;
// Set the Child property of Popup to the border
// which contains a stackpanel, textblock and button.
p.Child = border;
// Set where the popup will show up on the screen.
p.VerticalOffset = 400;
p.HorizontalOffset = 150;
// Open the popup.
p.IsOpen = true;
Does anyone know how I can accomplish the same thing in the XAML?
There are two ways of using a Popup. It can be an overlay control or it can be defined in the layout (or added to the tree) and it will take space like a standard control.
To have an overlay popup but avoid defining the layout in code-behind and still u, two techniques are often used:
1) defining the popup content as a separate user control. Your event handlers like Feedback_Click would now be definded in code-behind of the UserControl
var p = new Popup { Child = new MyControl() };
p.IsOpen = true;
2) defining the popup content simply in xaml in ResourceDictionary.
Related
Lately I am working on this personal app, it's form is without border so the Exit Button, Minimize Button and Maximize button, as well as the option to resize and move the form have been custom added. The app contains several User Controls which perform different functions such as Login, a Control Panel for the app and so on. The issue here is that the User Controls, which are placed within a panel (Anchored properly, of course) in the main form are not resizing properly when the window is in a Maximized state.
To detail... the app starts at
this size and while it's manually resized in minimized state the controls have no issue inheriting it's parent's (the panel) size,
like this and this also works if the window is maximized while the control is visible, like this however if the window is already in a maximized state and I call the control with the designated button the control does not resize, it stays to it's minimum dimensions, like so.
At first I thought it may have something to do with the code that resizes the form so I removed everything and made the app with the default windows border and controls, basically set the border Property from none to sizable but that did nothing. Also I have tried accessing the User Control's parent (the panel) using this.Parent and then setting the width and height of the control with Width = this.Parent.Width and Height = this.Parent.Height but the parent returns null for some reason which I am yet to understand. Now, worth mentioning that those user controls are dynamically added (i.e Login loginForm = new Login();) to the panel every time the button is clicked and then Disposed once the control is left.
I looked all over Google for this but found nothing related and at this point I am out of options. I really want the app to be resizable and must resize properly so if anyone has any solutions I am open to anything.
Thanks anticipated.
Meanwhile, for Winforms, I may have an answer.. the key is to use the Resize event of your user control(s), see below. I tested this in Core 3.1 and Net 4.7, you can use an default designer.cs unit with an empty form. It has no issues with resize from maximized state.
My user control for the center app is named CenteredPanel and derived from Panel. Make sure you derive your user controls from Panel and call base() on the constructor, else the docking will not work properly.
Also, your question about parenting: it was not needed to use Parent below, but if you really need it, make sure you assign it !
public partial class Form1 : Form
{
private Panel panel1, panel2, panel3, panel4;
private CenteredPanel panelApp;
public Form1()
{
InitializeComponent();
this.panel1 = new System.Windows.Forms.Panel()
{ Parent = this, Dock = DockStyle.Fill };
this.panel2 = new System.Windows.Forms.Panel()
{ Parent = panel1, Dock = DockStyle.Left, Width = 120, BackColor = Color.FromArgb(60, 60, 60) };
this.panel3 = new System.Windows.Forms.Panel()
{ Parent = panel1, Dock = DockStyle.Fill };
this.panel4 = new System.Windows.Forms.Panel()
{ Parent = panel3, Dock = DockStyle.Top, Height = 60, BackColor = Color.FromArgb(60, 60, 60) };
this.panelApp = new WindowsFormsAppCore.CenteredPanel()
{ Parent = panel3, Dock = DockStyle.Fill, BackColor = Color.FromArgb(90, 90, 90) };
this.panel1.Controls.Add(this.panel3);
this.panel1.Controls.Add(this.panel2);
this.panel3.Controls.Add(this.panelApp);
this.panel3.Controls.Add(this.panel4);
this.Controls.Add(this.panel1);
}
}
public class CenteredPanel : Panel
{
Label label1, label2;
TextBox textbox1;
public CenteredPanel() : base()
{
this.Resize += new System.EventHandler(this.Resizer);
this.label1 = new System.Windows.Forms.Label()
{ Parent = this, AutoSize = true, Name = "label1", ForeColor =Color.White, Text = "Connectare Administrator" };
this.label2 = new System.Windows.Forms.Label()
{ Parent = this, AutoSize = true, Name = "label2", ForeColor = Color.White, Text = "Nume de utilizator" };
this.textbox1 = new System.Windows.Forms.TextBox()
{ Parent = this, AutoSize = true, Name = "textbox1", PasswordChar = '*', Text = "****" };
this.Controls.Add(this.label1);
this.Controls.Add(this.label2);
this.Controls.Add(this.textbox1);
}
public void Resizer(object sender, EventArgs e)
{
Point CenteringAnchor = new Point(Width / 2, Height / 2);
for (int i=0; i<Controls.Count; i++)
{
Control c = Controls[i];
// put your resizing rules here.. this is a very simple one
c.Location = new Point(CenteringAnchor.X - c.Width / 2, -40 + i * ((i == 1) ? 40 : 30) + CenteringAnchor.Y - c.Height / 2);
}
}
}
I need to hide a TextBlock that is child of a Border and is added to a Grid. The following code dynamically add the Border and the TextBlock to the Grid. Then if the Grid contain more than 5 children it hide the firsts children. It work correctly to hide the border but the TextBlock (the child of Border) remain visible.
Any idea where could be the problem? Thanks!
Border TextBorder = new Border();
TextBorder.BorderBrush = new SolidColorBrush(_settings.TextColor);
TextBorder.BorderThickness = new Thickness(0,0,0,2);
TextBorder.Padding = new Thickness(0, 10, 0, 10);
RowDefinition rd = new RowDefinition();
rd.Height = GridLength.Auto;
myGrid.RowDefinitions.Add(rd);
TextBlock uc = new TextBlock();
uc.Text = "Test";
TextBorder.Child = uc;
Grid.SetRow(TextBorder, myGrid.RowDefinitions.Count -1);
myGrid.Children.Add(TextBorder);
if (myGrid.Children.Count > 5)
{
Border border = (Border)myGrid.Children[myGrid.Children.Count - 6];
border.Visibility = Visibility.Hidden;
border.Child.Visibility = Visibility.Hidden;
}
Update
The code work correctly. The problem was in OnRender event of the TextBlock that draw the text with some graphic effect. I though that if the control is invisible OnRender should not be raised but it seams that it is raised also when the control is invisible. I have not found a way to prevent OnRender to be raised, nor ClipToBound nor Invisible work. So I give up with this approach and I just check in OnRender if the TextBlock is in the visible area of the container.
first of all, I think what you do is something you should not do!
But here is how you can do it (btw this assumes you only add Borders to your grid):
if (myGrid.Children.Count > 5)
{
(myGrid.Children[myGrid.Children.Count - 6] as Border).Visibility = Visibility.Hidden;
}
also i recommend to remove not to hide the child as it will otherwise stay in existance without any point
myGrid.Children.Remove(myGrid.Children[0]);
I'm making a Button at runtime with a ViewBox and inside the ViewBox I'm adding a TextBlock. It all works fine, except I can't seem to get the text to left-align. After some fiddling, I realized this is because the TextBlock isn't the full width of the button.
var row = new RowDefinition();
OrdersGrid.RowDefinitions.Add(row);
var button = new Button();
button.HorizontalAlignment = HorizontalAlignment.Stretch;
button.VerticalAlignment = VerticalAlignment.Stretch;
button.MaxHeight = 40;
button.Background = (Brush)System.Windows.Application.Current.Resources["OrangeGradient"];
button.BorderThickness = new Thickness(.1);
button.Margin = new Thickness(.1);
OrdersGrid.Children.Add(button);
Grid.SetColumn(button, 0);
Grid.SetRow(button, rowNumber);
Viewbox vb = new Viewbox();
vb.StretchDirection = StretchDirection.Both;
vb.HorizontalAlignment = HorizontalAlignment.Stretch;
TextBlock tb = new TextBlock();
tb.HorizontalAlignment = HorizontalAlignment.Stretch;
tb.Text = rowNumber + " - " + CustomerName;
tb.Padding = new Thickness(0);
tb.TextAlignment = TextAlignment.Left;
vb.Child = tb;
button.Content = vb;
If I change tb.HorizontalAlignment = HorizontalAlignment.Stretch; to tb.Width = 400; it left-aligns. However, I have no guarantee that that is the correct size, but it does narrow the problem down to the width of the TextBlock. How can I make the TextBlock (And ViewBox) the full width of the Button?
Set the HorizontalContentAlignment property of the Button to Left:
button.HorizontalContentAlignment = HorizontalAlignment.Left;
Why do you want to make the contents the full width of the button? What visual or functional difference would that make? I don't see anything in your code that would require that. If the TextBlock had a background brush of its own, that would be a reason, but it doesn't.
If you absolutely did need to left center the text within something stretched, put a Border around the ViewBox inside the button, set Button.HorizontalContentAlignment = Stretch, and set ViewBox.HorizontalAlignment = Left.
The bottom line here is that the Button's content is by default centered in the Button's content area, and Button.HorizontalContentAlignment controls that. Its default value is Center. If you want to force the content to stretch, set it to Stretch.
If you really just want to left justify the content, just use mm8's answer. Quick and easy.
I need to measure the DesiredSize or ActualHeight/Width of a button (and radio button) without actually putting it onto the visual tree but I keep getting back non-sense values. This same approach works when measuring other controls such as TextBlock.
var button = new Button
{
Content = "Hello World",
FontSize = 15
};
button.Measure(new Size(maxWidth, double.PositiveInfinity));
var height = button.DesiredSize.Height;
var width = button.DesiredSize.Width
I'm getting back 21px for height and 0px for width. Any idea why I'm getting 0 back for width?
I need to measure the DesiredSize or ActualHeight/Width of a button (and radio button) without actually putting it onto the visual tree but I keep getting back non-sense values.
If you assign a string value to Button.Content, the value will be assigned to the inside TextBlock through Binding in runtime, which happens after the Button.Measure (You can see this by adding the button to the page and check the LiveProperty Explorer):
So you get the wrong desired size.
As a workaround, you can create a TextBlock and assign this TextBlock to the button:
var tbContent = new TextBlock()
{
Text = "Hello World",
FontSize=15
};
var button = new Button
{
Content = tbContent,
};
var h= button.DesiredSize.Height;
button.Measure(new Size(200, double.PositiveInfinity));
var height = button.DesiredSize.Height;
var width = button.DesiredSize.Width;
Then you will get the correct Size of this button.
I'm guessing that this isn't possible. You're measuring the button before it has loaded its template.
I can only suggest doing something like this:
var but = new Button();
but.Content = "Hello";
var popup = new Popup();
popup.Child = but;
popup.IsOpen = true;
popup.Visibility = Visibility.Collapsed;
but.Loaded += (s, e) =>
{
System.Diagnostics.Debug.WriteLine(but.RenderSize);
popup.IsOpen = false;
};
But it's kind of hacky, and the button won't load until some later time, making this whole process asynchronous which might be difficult to manage.
I'm using a Dockpanel via C# & WPF to display 2 user controls
The Left UserControl is a Datagrid with Filters (Called Filter)
The Right UserControl is a Custom Form That will change depending on what type of Data the user is viewing.
I'm setting the Dockpanel via this code
private void SetMasterDock(UIElement MyFilter, UIElement NewViewer)
{
MasterDock.Children.Clear();
DockPanel.SetDock(MyFilter, Dock.Left);
DockPanel.SetDock(NewViewer, Dock.Right);
MasterDock.Children.Add(MyFilter);
MasterDock.Children.Add(NewViewer);
}
All the above works as coded.
Now the Change I'm looking for (If possible)
I'd like to know what / how to enable the User to be able to Adjust the Scaling of the two Usercontrols. so if they wish to see More or less of one side or the other, they can just Click & Slide a Divider bar so they can adjust their view to their personal preferences.
ETA: New Code
MasterDock.Children.Clear();
Grid SplittableGrid = new Grid();
GridSplitter MovableDevider = new GridSplitter(); MovableDevider.Background = Brushes.Blue; MovableDevider.HorizontalAlignment = HorizontalAlignment.Right; MovableDevider.VerticalAlignment = VerticalAlignment.Stretch; MovableDevider.Width = 5;
ColumnDefinition LeftDefinition = new ColumnDefinition(); LeftDefinition.Width = new GridLength(200);
ColumnDefinition RightDefinition = new ColumnDefinition(); RightDefinition.Width = new GridLength(1,GridUnitType.Star);
SplittableGrid.ColumnDefinitions.Add(LeftDefinition);
SplittableGrid.ColumnDefinitions.Add(RightDefinition);
Grid.SetColumn(MyFilter, 0);
Grid.SetColumn(MovableDevider, 0);
Grid.SetColumn(NewViewer, 1);
SplittableGrid.Children.Add(MyFilter);
SplittableGrid.Children.Add(MovableDevider);
SplittableGrid.Children.Add(NewViewer);
DockPanel.SetDock(SplittableGrid, Dock.Left);
MasterDock.Children.Add(SplittableGrid);
in winforms the control you are looking for is the splitcontainer. However in WPF this is done using grid + gridSplitter. both of those controls are in the default toolbox.