Creating binary tree with wpf - c#

I'm trying to create a binary tree in wpf that will look like that:
So, I created three classes - Node (Abstract), And OneTypeNode, And TwoTypeNode (those are example, btw, MVVM is important here).
Every node also have reference to his two sons.
in the xaml, it look something like that:
<StackPanel>
<Grid ShowGridLines="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Border Grid.Column="1" Grid.Row="0" x:Name="CircleFather" CornerRadius="5"
Width="40"
Height="40"
Background="DarkKhaki"
Margin="0 20 0 0"
BorderThickness="1" >
</Border>
<ContentControl Grid.Row="2" Grid.Column="0" Content="{Binding RightSon}" Margin="10"></ContentControl>
<ContentControl Grid.Row="2" Grid.Column="2" Content="{Binding LeftSon}" Margin="10"></ContentControl>
</Grid>
<Line ></Line>
</StackPanel>
Which actually let me create sons recursively!
But there are two main problems: first of all is the size, I can't control the size of the grid since I don't know how many sons are gonna be on every side. ALSO - I don't have any idea to how create the lines between every two nodes. Any idea?
Thank you very very much!

Related

SfDataGrid overlapping with existing content using MAUI and .NET 7

I've created a table using the SfDataGrid plugin as well as a standard Stacklayout template to load other data.
I've contained both in a <Grid>. Both load, however, they load on top of each other / under the table
The general Hierarchy of the page is as follows
<Grid>
//declare Grid and following columns
<syncfusion:SfDataGrid>
<syncfusion:SfDataGrid.Columns>
</syncfusion:SfDataGrid.Columns>
</syncfusion:SfDataGrid>
//Declare Dropdowns and filters contained in a StackLayout
<StackLayout Grid.Row="3" Grid.Column="0" Grid.RowSpan="5">
</StackLayout>
</Grid>
This image demonstrates the issue occurring. As you can see the secondary data(the dropdowns) overlap on top of the table data, where it should be positioned at the bottom
Output
you have to specify the Row and Column each element should appear in, otherwise they will be placed on top of one another in 0,0. This is covered in the docs
<Label Grid.Row="5" Grid.Column="2" ... />
There are two solutions that you can adjust the place of the the dropdowns at the bottom of the SfDataGrid.
#1 Solution:
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Grid.ColumnSpan="5">
//SfDataGrid Control
</Grid >
<Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="5" >
<Button Text="test" WidthRequest="100" HeightRequest="20"/>
</Grid>
</Grid >
Note: I used a Button to replace Dropdowns and filters contained in a StackLayout. You can replace it back with Dropdowns and filters.
#2 Solution:
Set VerticalOptions="End" like below:
<Grid >
<Grid >
//SfDataGrid Control
</Grid >
<StackLayout VerticalOptions="End">
<Button Text="test" WidthRequest="100" HeightRequest="20"></Button>
</StackLayout>
</Grid >

Select center control/column

I have a grid with multiple controls and I want to choose which of these controls (or which of the grid columns) will be in the center, and then have the other columns/controls just placed adjacent to it. How would I do that?
Update:
The following pattern:
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="MainControl's height"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="MainControl's width"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
will always force MainControl to be centered, as long as other controls will be defined in the * parts. In other words if position [1,1] in the above Grid contains your MainControl, you can define different Grids with different row/column definitions for positions [0,0], [0,1], ..., [2,2] to wrap more controls with custom size in custom locations.
For example this xaml:
<Window Title="MainWindow" Height="600" Width="800" >
<Grid x:Name="myGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="200"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Row="0" Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="50"/>
<RowDefinition Height="80"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70"/>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Content="0,0"/>
<Button Grid.Row="0" Grid.Column="1" Content="0,1"/>
<Button Grid.Row="1" Grid.Column="1" Content="1,1"/>
<Button Grid.Row="2" Grid.Column="2" Content="2,2"/>
</Grid>
<Button Background="LightBlue" Grid.Row="1" Grid.Column="1" Content="1,1"/>
<Grid Grid.Row="2" Grid.Column="2">
<Grid.RowDefinitions>
<RowDefinition Height="80"/>
<RowDefinition Height="35"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="90"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Content="0,0"/>
<Button Grid.Row="1" Grid.Column="0" Content="1,0"/>
<Button Grid.Row="1" Grid.Column="1" Content="1,1"/>
<Button Grid.Row="2" Grid.Column="0" Content="2,0"/>
<Button Grid.Row="2" Grid.Column="2" Content="2,2"/>
</Grid>
</Grid>
</Window>
Will locate the controls this way:
What are you trying to achieve in terms of layout? Your grid strategy will determine how the whole layout behaves, especially if you expect it to scale in regards to the window size. If you want the layout to react to the window size, then you use "Auto" and "Star sizing" strategies. If you actually don't care about resizing and you expect a fixed layout, then you can share grid sizes across columns.
Scenario 1-
If you are trying to purely achieve a middle column which contains objects of unknown size, and this column must be perfectly centered, then you need to buffer this middle column with a left and right column, as per Bahman_Aries' example.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
</Grid>
The result from this is that items placed in the middle column will consume as much width as they need (the desired render width), and the two left over columns will split in two the remaining space, because each have a value of 1*. In other words, if your middle column object requests 200 width, and your window has 1000 total width, the left and right columns will both have 400 (800/2).
Note that star sized columns will crop your content when you reduce the window size. This is by design. You could consider wrapping your layouts in ViewBoxes (or the whole grid) if you want your ratios to persist.
Scenario 2-If you are looking for just a grid which lays out content with no regards to scaling, (re: the middle column consumes what it needs, and then the left and right columns grow equally when they have large content) then you can use the SharedSizeScope feature.
<Grid IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="MyRatio"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="MyRatio"/>
</Grid.ColumnDefinitions>
</Grid>
What this will achieve is that whenever your column 2 grows, it will also propagate its size to column 0, essentially ensuring that your column 1 is always centered.
The main difference from Scenario 1 is that Scenario 2 will have a fixed size according to its child elements, whereas Scenario 1 has a structure which behaves in accordance to its parent container.
Edit: Scenario 1 with an explicit example:
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="4*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<StackPanel Grid.Row="1" x:Name="TheLeftComponents" Orientation="Horizontal" HorizontalAlignment="Right" >
<Ellipse Height="20" Width="20" Stroke="Black" StrokeThickness="1" ></Ellipse>
</StackPanel>
<Ellipse x:Name="TheMiddleComponent" Grid.Row="1" Grid.Column="1" Height="40" Width="40" Stroke="Black" StrokeThickness="1" ></Ellipse>
<StackPanel Grid.Row="1" Grid.Column="2" x:Name="TheRightComponents" Orientation="Horizontal" HorizontalAlignment="Left" >
<Ellipse Height="20" Width="20" Stroke="Black" StrokeThickness="1" ></Ellipse>
<Ellipse Height="20" Width="20" Stroke="Black" StrokeThickness="1" ></Ellipse>
<Ellipse Height="20" Width="20" Stroke="Black" StrokeThickness="1" ></Ellipse>
<Ellipse Height="20" Width="20" Stroke="Black" StrokeThickness="1" ></Ellipse>
<Ellipse Height="20" Width="20" Stroke="Black" StrokeThickness="1" ></Ellipse>
</StackPanel>
</Grid>

How to bind 2 grid column widths together in xaml

I'm hoping someone can make this easy.
I have a grid with 5 columns, columns 1 and 3 contain splitters. What I want to happen is when I move one splitter have the other one move to match such that the effect is the first and last columns being sized together.
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" x:Name="col1"/>
<ColumnDefinition Width="5" />
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="5" />
<ColumnDefinition Width="{Binding ElementName=col1, Path=ActualWidth}" />
</Grid.ColumnDefinitions>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" Background="Red"/>
<GridSplitter Grid.Column="3" HorizontalAlignment="Stretch" Background="Red"/>
</Grid>
Needless to say the above doesn't work. And even if it did it would only allow for using the first splitter not the second. Can anyone shed some light?
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" x:Name="col1"/>
<ColumnDefinition Width="5" />
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="5" />
<ColumnDefinition Width="{Binding ElementName=helperGrid, Path=ActualWidth}" />
</Grid.ColumnDefinitions>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" Background="Red"/>
<GridSplitter Grid.Column="3" HorizontalAlignment="Stretch" Background="Red"/>
<Grid Grid.Column="0" x:Name="helperGrid" Width="{Binding ElementName=helperGrid2, Path=ActualWidth}" MinWidth="100"/>
<Grid Grid.Column="4" x:Name="helperGrid2"/>
</Grid>
This worked for me, I changed the first column's width to auto and used two helper grids in the first and last columns
After much playing around I could get close but not completely what I was looking for. So I ended up placing a Grid in each if the splitter columns instead of GridSplitters and handling the PreviewMouseDown event on the Grid and also the PreviewMouseUp and PreviewMouseMove events of the parent control to implement my own resizing. This was used to detect dragging in columns 1 and 3 and resize colunmns 0 and 3 together. Sadly the code has become rather interwoven with the rest of my control so isn't easy to post. Maybe one day when my xaml improves I'll be able to break the functionality out into a properly reusable control.

Windows Phone TextWrapping doesn't work in grid

I have a problem with my application. I want tomake a page, that will be show user notifications in the Grid. At the left side will be profile picture, at the right side profile name, message contents and time.
I have a problem with the TextBlock which contains message content.
TextWrapping doesn't seem to work. Message contents are displayed in single line, and they are cut in half.
<ListBox Name="listaWpisow" SelectionChanged="listaWpisow_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0,0,0,10" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<Image Source="{Binding av_url_64, Converter={StaticResource imgConv}}" Height="64" Width="64" Name="pictureBox" Grid.Row="0" VerticalAlignment="Top" HorizontalAlignment="Left"></Image>
</Grid>
<Grid Grid.Column="1" Margin="25,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding login}" TextWrapping="Wrap" FontWeight="Bold" Grid.Row="0" Grid.Column="0"></TextBlock>
<TextBlock Text="{Binding content}" TextWrapping="Wrap" Grid.Row="1" Grid.Column="0"></TextBlock>
<TextBlock Text="{Binding datetime_str}" FontSize="12" TextWrapping="Wrap" Grid.Row="2" Grid.Column="0"></TextBlock>
</Grid>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
How to solve this problem?
The problem is that your columns are set to width="Auto" This will let them grow as much as they want In practise this will grow as much as needed to accomodate all the content.
You should change it like so:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="3*"></ColumnDefinition>
</Grid.ColumnDefinitions>
This will keep the ratio equal: the second column is three times the width of the first. (you should tweak this to your specific need)
Note that this needs to be done on your outer-grid since the outer grid lets the inner grid grow as much as needed, and the innergrid grows as much as needed to accomodate the long text in the textbox

How to create this layout in WPF (3 controls)?

I made this image that shows the controls. The top one is a ListView and the others are ListView controls as well with additional controls.
But I can't figure out how to layout them to look like that.
Currently I use 3 DockPanels for each ListView where the top one uses Top VerticalAlignment, the others use Bottom for VerticalAlignment, Left and Right (for HorizontalAlignment).
But when I look at it, the other 2 controls appear after the top ListView to its right side. I can see this when I scale the top DockPanel to half the size, then the other 2 DockPanels show up, attached to the top DockPanel's right side.
Any ideas on how to fix this?
How about this?
The grid has no fixed widths or heights and should accommodate whatever controls you add.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Background="Aqua" Height="100"/>
<StackPanel Grid.Row="2" Grid.Column="0" Background="Orange" Height="100" Width="150" VerticalAlignment="Bottom"/>
<StackPanel Grid.Row="2" Grid.Column="2" Background="Green" Height="60" Width="200" VerticalAlignment="Bottom"/>
</Grid>
Initial window
Resized window
EDIT in response to comment
If you want a progressbar in the top panel, just use:
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"
Background="Aqua" Orientation="Vertical">
<ListView Height="50" Background="Purple"></ListView>
<ProgressBar Height="20" IsIndeterminate="True" ></ProgressBar>
</StackPanel>
Do you need them to be DockPanels, or this is a fixed layout?
If it's fixed you could do something like this:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="80"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
</Grid.ColumnDefinitions>
<ListView Grid.Row="0" Grid.RowSpan="1" Grid.Column="0" Grid.ColumnSpan="3" Name="dockPanel1" Background="CadetBlue">
</ListView>
<ListView Grid.Row="2" Grid.RowSpan="2" Name="dockPanel2" Background="Cyan">
</ListView>
<ListView Grid.Row="3" Grid.RowSpan="1" Grid.Column="2" Name="dockPanel3" Background="DarkRed">
</ListView>
</Grid>
I made the area between your three panels re-sizable as your window resizes.
Instead of the listviews that I used, you can put pretty much anything, a user control, another grid, whatever.
The colors will show you where the listview sections are easily.
You will probably want to adjust the sizes, or change the resize behavior.
You can learn more about grids here
Seems like this is the sort of scenario Alignment, Margins, and Padding are made to handle...

Categories

Resources