Im working on creating StackPanels in C#.
The xaml Im trying to replicate in C# is
<StackPanel Grid.Column="0" Background="BlanchedAlmond" DragOver="panel_DragOver" Drop="panel_Drop" AllowDrop="True" MinWidth="150">
Currently what I have is:
StackPanel myPanel = new StackPanel
{
MinWidth = 150,
MinHeight = 150,
AllowDrop = true
};
MainStack.Children.Add(myPanel);
Which currently works the only issue is that the StackPanel does not have the properties for DragOver and Drop, how can I add this to the C# code?
These are not properties but events that you can hook up handlers to using the += syntax:
StackPanel myPanel = new StackPanel
{
MinWidth = 150,
MinHeight = 150,
AllowDrop = true
};
myPanel.DragOver += panel_DragOver;
myPanel.Drop += panel_Drop;
MainStack.Children.Add(myPanel);
Of course the handlers, panel_DragOver and panel_Drop, must still be defined just like before.
Yes, it does have it.
var sp = new StackPanel();
sp.Drop += (o, arg) => { };
You just cannot assign an event within the body of object creation.
Related
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 try to add an scroll Viewer for a text block who was created from behind c#, text block was added to a stack panel stackPanel.Children.Add(text block). I want to do that in Windows Phone 8.0.
When make something like that:
StackPanel stackPanel = new StackPanel();
ScrollViewer sv = new ScrollViewer();
sv.Content = stackPanel;
I receive:
ExceptionObject = {"Value does not fall within the expected range."}.
One solution to solve that exception?
ScrollViewer calculates it's scrollbars based on dimensions of child controls.
If your TextBlock has Height property set, remove it and ScrollBars should work as expected.
Also you should set:
sv.Content = yourTextBlock;
With the following code (where Content is Grid):
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var textBlock = new TextBlock() { Text = "hello" };
var stackPanel = new StackPanel();
stackPanel.Children.Add(textBlock);
var sv = new ScrollViewer { Content = stackPanel };
this.Content.Children.Add(sv);
}
I get the desired output:
So I tried to reproduce your error. I get the same exception if TextBlock is null. So maybe your code which creates the TextBlock has some issues? Here's an example:
TextBlock text = null;
var stackPanel = new StackPanel();
stackPanel.Children.Add(text);
var sv = new ScrollViewer { Content = stackPanel };
this.Content.Children.Add(sv);
Will result in:
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.
I have written a custom WPF UserControl. It's a square with a Grid named Base. To that grid I add an ellipse and two labels (volume and location), which are populated with text pulled from the properties of an object which is given as a parameter upon control instantiation.
Here's the XAML:
<UserControl x:Class="EasyHyb.SampleWellControl"
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="100" d:DesignWidth="100">
<Grid x:Name="Base">
</Grid>
</UserControl>
And the constructor/event functions in the codebehind:
public SampleWellControl(int size, SourceSample sample)
{
InitializeComponent();
this.sample = sample;
this.Width = this.Height = size;
this.selected = SelectionStatus.Unselected;
double spacing = size / 4;
volume = new Label();
location = new Label();
volume.Content = String.Format("{0:0.00}", sample.volume);
location.Content = sample.well.well;
volume.HorizontalAlignment = location.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
volume.FontFamily = location.FontFamily = new System.Windows.Media.FontFamily("Meiryo UI");
volume.FontWeight = location.FontWeight = FontWeights.Bold;
volume.Background = location.Background = Base.Background = this.Background = Brushes.Transparent;
volume.Margin = new Thickness(0, spacing, 0, 0);
location.Margin = new Thickness(0, spacing * 2, 0, 0);
well = new Ellipse();
well.Width = well.Height = this.Width;
well.StrokeThickness = 3;
Base.Children.Add(well);
Base.Children.Add(volume);
Base.Children.Add(location);
this.MouseEnter += SampleWellControl_MouseEnter;
this.MouseLeave += SampleWellControl_MouseLeave;
this.MouseUp += SampleWellControl_MouseUp;
this.Cursor = Cursors.Hand;
UpdateFillAndStroke();
}
void SampleWellControl_MouseLeave(object sender, MouseEventArgs e)
{
RevertWell();
}
void SampleWellControl_MouseEnter(object sender, MouseEventArgs e)
{
HighlightWell();
}
public void HighlightWell()
{
if (this.selected == SelectionStatus.Pooled)
{
return;
}
if (this.selected == SelectionStatus.Unselected)
{
this.well.Stroke = this.strokes[SelectionStatus.Selected];
}
else
{
this.well.Stroke = this.strokes[SelectionStatus.Unselected];
}
}
public void RevertWell()
{
if (this.selected == SelectionStatus.Pooled)
{
return;
}
if (this.selected == SelectionStatus.Unselected)
{
this.well.Stroke = this.strokes[SelectionStatus.Unselected];
}
else
{
this.well.Stroke = this.strokes[SelectionStatus.Selected];
}
}
Basically, when the mouse enters the control, the stroke of the ellipse should change unless the well has undergone an operation to give it a "Pooled" status.
When the mouse enters the control, it responds exactly as I expect: the MouseEnter event handler fires. However, when a user moves the mouse over one of the labels inside the control, the MouseLeave event fires. So even though the label is ostensibly part of the control The pictures below show what I'm talking about. Print Screen removes the cursors, but I put blue dots to indicate where the cursor is:
Responding properly:
Now it seems to think the mouse has left the control:
I've tried adding MouseEnter and MouseLeave event handlers to the labels, but they don't fire. The cursor also changes from a hand to a pointer when the labels are moused over. I've tried adding MouseEnter and MouseLeave event handlers to the control after it's instantiated within another class. I added transparent backgrounds to the Grid, control, and labels, but that didn't make any difference either.
I also checked in my MouseLeave event handler to see if the mouse was over the control, and it seems that the control is not detecting the cursor as being over the control itself:
if(!this.IsMouseOver)
{
RevertWell();
}
//also tried IsMouseDirectlyOver
I would like MouseLeave to fire only when the cursor exits the square bounds of the control. How can I accomplish this while keeping the labels?
Use a combination of
IsHitTestVisible="False"
on all of your objects added to Base:
volume = new Label();
volume.IsHitTestVisible="False";
and then your container which has the events, give a background
<Grid x:Name="Base" Background="White">
(Also I wanted to comment but reputation is stupid)
Well shucks, after a lot of searching around it turns out the problem was indeed contained within another control. I had another UserControl class, EmptyWellControl, which had a Label. The text position within the label was calculated using the Label's Height property, which resulted in a nonsense value that made the label extend vertically well beyond the dimensions of the window. The label didn't have a background, but nevertheless interfered with the controls whose path it crossed. Since the empty and sample wells were all laid out on the same grid, every SampleWellControl was affected by these labels.
I create a StackPanel in run-time and I want to measure the Height of the StackPanel like this:
StackPanel panel = new StackPanel();
panel.Children.Add(new Button() { Width = 75, Height = 25 });
Title = panel.ActualHeight.ToString();
but ActualHeight is alwasy zero. How can I measure the Height Of the StackPanel?
In case you want to measure size without loading content on UI, you have to call Measure and Arrange on containing panel to replicate GUI scenario.
Be notified that how's WPF layout system works, panel first calls Measure() where panel tells its children how much space is available, and each child tells its parent how much space it wants. and then Arrange() is called where each control arranges its content or children based on the available space.
I would suggest to read more about it here - WPF Layout System.
That being said this is how you do it manually:
StackPanel panel = new StackPanel();
panel.Children.Add(new Button() { Width = 75, Height = 25 });
panel.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
panel.Arrange(new Rect(0, 0, panel.DesiredSize.Width, panel.DesiredSize.Height));
Title = panel.ActualHeight.ToString();
Try get the ActualHeight in Loaded event:
private void Button_Click(object sender, RoutedEventArgs e)
{
var panel = new StackPanel();
var button = new Button();
button.Width = 75;
button.Height = 25;
panel.Children.Add(button);
panel.Loaded += new RoutedEventHandler(panel_Loaded);
MainGrid.Children.Add(panel);
}
private void panel_Loaded(object sender, RoutedEventArgs e)
{
Panel panel = sender as Panel;
Title = panel.ActualHeight.ToString();
}
I'm not entirely sure what you're trying to do, but this code works:
this.SetBinding(Window.TitleProperty,
new Binding()
{
Source = panel,
Path = new PropertyPath("ActualHeight")
});
In general, you won't be able to access the size of a stackpanel until it is laid out and rendered. This happens prior to the panel's Loaded event, so you could handle that event and deal with it then.
Try this:
panel.UpdateLayout(); //this line may not be necessary.
Rect bounds = VisualTreeHelper.GetDescendantBounds(panel);
var panelHeight = bounds.Height;