Connect the sides of two datagrids - wpf

I'm having some difficulties with formatting two datagrids so that they resize appropriately when their containing window is resized. Currently, the two datagrids are sitting side by side so that they nearly touch in the center of the window.
The top, bottom, and edge-facing sides of each datagrid are connected/linked to the nearest side of the window (I used the link icon in the center of each side). Is there a way to make the center facing sides of the datagrids connect to each other (or to the center of the window), so that when the window is resized, these center-facing sides stay close to the center?
Thanks in advance for any help!

From the way you ask your question, I believe you're coming from WinForms development. In WPF, things are a lot different. I would suggest that you get a WPF book and start writing the XAML directly and not use the designer.
For your problem, the solution is pretty straightforward. All you have to do is use a grid with 2 columns:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<DataGrid Grid.Column="0"></DataGrid>
<DataGrid Grid.Column="1"></DataGrid>
</Grid>
The Width="*" attribute will make sure that the columns are the same width and that they take up all available space.
The trouble with using the designer is that when you do that, it will start putting hardcoded margins and sizes in your XAML and you will lose all of the cool auto-sizing features of WPF. Therefore I strongly suggest writing XAML manually and not using the designer (except to see what your window/control looks like).

Related

(WPF/XAML) How can I create a responsive toolbar similar to the one from Window's Snipping Tool?

I'm trying to create a responsive toolbar in WPF that works like the one in the in Windows Snipping Tool (the one that opens if you press Win+Shift+S).
The Snipping Tool's toolbar has 3 groups of buttons. When you change the size of the window, the space between the groups changes, while the groups maintain their original width.
Small window
Big window
If you make the window any smaller than in the first image, it separates into 2 toolbars. But don't worry about that, I can simply set a minimal width to my app, I don't really care about that part.
What I want is the same spacing effect on my toolbar, I have 3/4 groups of buttons but I can't get them to do the same.
I tried using grids for the groups of buttons, and putting the groups inside another grid as the toolbar, but when I resize the window some of the content starts to disappear even tho there's some space left.
I was going to just write a comment but I think I need some xaml for clarity.
Wpf has proportional sizing uses gridlength. You can have columns ( or rows ) use multiples of * to divide up whatever space is unused. Thus:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" Name="SomeButtonsGoHere"/>
<ColumnDefinition Width="*" Name="ProportionallySpacedColumnBetweenButtons"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
You could put say a uniformgrid with just one row in each of the fixed size columns and buttons inside that.
Your Buttons probably aren't 100px wide of course.
But if you put that grid in a window, the fixed size columns will retain size and the * sized ones will fill up the remaining space equally.
Once you had something relatively simple working you can think about iterating. You could use a converter to calculate sizes compare to window width, viewbox to shrink content proportionally. Sounds like that's over complicating things though.

Dynamic scrolling in a WPF application with ItemsControl object

In my xaml, I have some object made by me. I put them in row and, if the window is too little for all, I go in a new line.
The problem is when the window is so little that, also in a new line, the elements can't be all shown. The solution is simple: scroll bar!! But, if I set the Vertical/HorizontalScrollBarVisibility to auto, it doesn't go to a newline anymore.
This is my xaml:
<ScrollViewer CanContentScroll="True" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Disabled" >
<ItemsControl Name="ItemGroups" ItemsSource="{Binding NotifyItemUI}" />
</ScrollViewer>
and this is a screenshot what I need as my goal:
For example, if I resize my area vertically, and I have 3 rows of objects, in this way I can't see the third row if the window becames too little. In this case, I'd like to see a vertical scrollbar to scroll it.
Same thing horizontally: if I have too many elements for one single row, I have to scroll it horizontally.
What you describe looks like a WrapPanel, but the way you write about it suggests it is a custom control, so we cannot see what your ItemsControl is doing for layout.
However, ScrollViewer can have tricky interaction with a Panel. If the Panel measures to infinity, it will always consider itself big enough, and never tell the ScrollViewer it is out of room. The result is that the ScrollViewerdoes no know the scrollbar is needed. If this is your problem, then setting the Width and Height properties, or maxima as #Sheridan said, ought to fix it.

WPF control origin point

After some investigation, I still can't find method to change origin of control.
So, I want just to place one square exactly in center of another square, without margins, so it will be completely independent of first square size.
Theoretically, it can be easily done with HorizontalAlignment and VerticalAlignment set to Center, since it automatically sets Margin of control to half of width and height of parent control. But it is not so simple.
Simplest way to describe problem is next picture
As you can see, margin is counted towards upper left corner. Which is what I call origin. The perfect solution is to change it to center of first square, but this is where I need help - how can I do that?
Point of origin applies when using a transform object, and attaching the transform to your control. It won't actually effect the behaviour of the margin or left, top properties. If using a transform to place your object, point of origin is very useful.
The top, left (if using cavas) and margin (if using say grid) help govern the "auto" placement by the parent control, and this in turn governs where point of origin for the control winds up being relative to the parent control. The transform object then offsets RELATIVE to where that point of origin is.
The other useful thing is that transform overrides the auto placement in the parent control, or rather, forces an offset to where the parent wants to put it, which in some cases is useful - i.e., you might have boxes listed in a grid and want them to "shake" left and right when you hover the mouse over them, their alignment stays in order to the grid, but the transform lets you bump them away from their "forced" position.
For example, attach the same transform object to 2 controls, and set their origins separate, then apply an animation to the transform object - both controls will animate off the one animation object (if you wanted to their movement in perfect sync).
Well, it was weird enough. The given behaviour can be seen only when using Image, and Center alignment. Can be solved by either wrapping Image in Grid, which will be using Center alignment, or using Stretch alignment with Image (which is much simplier).
<Grid Width="500" Height="500">
<Image Width="250" Height="250" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
</Grid>
If you want to reproduce problem I've described in question, replace Stretch with Center in code above.
Probably oversimplifying here but I would just use a Grid to wrap the two items you mentioned like this example (One stretched to fit and one centered):
<Grid>
<Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderBrush="Black" BorderThickness="10" Margin="4"/>
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Padding="10">InnerButton</Button>
</Grid>

Silverlight: Place an element at the top of the screen?

It is idiomatic in Windows Phone 7 to display a loading indicator at the very top of the screen. (I don't think there is any padding between the loading indicator and the top.)
What is the best way to do that in Silverlight? This XAML works, sorta:
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- this needs to be at the very top of the screen -->
<ProgressBar x:Name="LoadingProgressBar" IsIndeterminate="True" Style="{StaticResource PerformanceProgressBar}" Grid.Row="0"/>
<controls:Pivot Title="SECTIONS" x:Name="pivotControl" SelectionChanged="pivotControl_SelectionChanged" Grid.Row="1" />
</Grid>
It places the ProgressBar near the top of the screen, but there's still space. I could just apply a negative margin, but I suspect there's a more elegant way. What is the preferred way of doing this?
Have a look in the definition of the PhoneApplicationPage. Is shell:SystemTray.IsVisible set to True of False?
My guess is that you've got it set to True (the default).
If this is the case then space at the top of the page will be reserved to display the system tray. (Which includes signal strength, battery level indicator, clock, etc.) If you change this to False then the layout engine will use all available space for your controls.
The downside to this is that the user won't be able to access the tray while your app is running.
While it's common to put an inditerminate wait indicator at the top of the screen, it's also not unusual to see it in the middle of the screen. Subject to what you're actually displaying on the page, you could consider this if you want to preserve the ability to see the system tray.
Alternatively you could use a completely custom wait cursor.
Your code works for me. I pasted your code in, replacing your Pivot control for a button.
What are you seeing?
Inbuilt in the windows phone control templates is metro styling. As you say you can use the likes of negative margins (or paddings in controls I've looked at)... iirc, the progressbar has styling such that if the height is not a minimum of 73 pixels then the progressbar is obscured.
Alternatively you can go to the source of this by retemplating the control in blend and controling the properties in the consituent components that make up the control.
To do this, rclick the control in blend, edit template, edit a copy and you're away.

How can I line up WPF items in a Horizontal WrapPanel so they line up based on an arbitrary vertical point in each item?

I'm trying to create a View in WPF and having a hard time figuring out how to set it up. Here's what I'm trying to build:
My ViewModel exposes an IEnumerable property called Items
Each item is an event on a timeline, and each one implements ITimelineItem
The ViewModel for each item has it's own DataTemplate to to display it
I want to display all the items on the timeline connected by a line. I'm thinking a WrapPanel inside of a ListView would work well for this.
However, the height of each item will vary depending on the information it displays. Some items will have graphic objects right on the line (like a circle or a diamond, or whatever), and some have annotations above or below the line.
So it seems complicated to me. It seems that each item on the timeline has to render its own segment of the line. That's fine. But the distance between the top of the item to the line (and the bottom of the item to the line) could vary. If one item has the line 50 px down from the top and the next item has the line 100 px down from the top, then the first item needs 50 px of padding so that the line segments add up.
I think I could solve that problem, however, we only need to add padding if these two items are on the same line in the WrapPanel! Let's say there are 5 items and only room on the screen for 3 across... the WrapPanel will put the other two on the next line. That's ok, but that means only the first 3 need to pad together, and the last 2 need to pad together.
This is what's giving me a headache. Is there another approach I could look at?
EDIT: I'm leaning towards replacing the WrapPanel with a custom panel that inherits from Canvas and overrides the MeasureOverride and ArrangeOverride methods.
The ideal solution to this would probably be using Adorners. On the AdornerLayer you would have a custom Adorner for each item on the Panel (you define it in the DataTemplate). You will be able to retreive dimensions an positions of each item (Boundingbox of the Adorner). Also on the AdornerLayer you would then draw the lines between these boundingboxes.
Using this solution you can layout your items any way you want (using any Panel you want) and the items will still be connected with lines.
A long time ago I used this approach for a graph visualizer. The nodes where arbitary UIElements that could be layouted in any way. The items where connected with lines.
To make all items align perfectly you could use a Canvas as the root Panel in you ItemTemplate. The Canvas can be 0x0 units big. You would then arrange your elements around that Canvas. The Canvas becomes your point of reference. Everything on top of the line will get negative Canvas.Top values.
Another approach would be to use negative margins that are bound to the height of the top and bottom controls that surrond the line. Use a IValueConverter (Height*-1) to invert the Height.
This won't solve your problem, but I bet it will simplify it:
Try defining a DataTemplate that looks something like this:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" SharedSizeGroup="Top"/>
<RowDefinition Height="10"/>
<RowDefinition Height="Auto" SharedSizeGroup="Bottom"/>
</Grid.RowDefinitions>
<ContentControl Grid.Row="0" Content="{Binding TopAnnotations}/>
<Rectangle Fill="Black" Grid.Row="1" Margin="0,4,0,4"/>
<ContentControl Grid.Row="1" Height="10" Content="{Binding GraphicObject}"/>
<ContentControl Grid.Row="2" Content="{Binding BottomAnnotations}"/>
</Grid>
Now create an ItemsControl whose ItemsPanelTemplate is a horizontal WrapPanel with the Grid.IsSharedSizeScope attached property set to True. You will of course also need to define data templates for whatever the annotation and graphic object properties contain.
You still have the problem that when the items in the WrapPanel wrap, the objects above and below the timeline have the same padding irrespective of how much they actually need to fit on their current row of the WrapPanel. So to get the effect that I think you're looking for, you still have to monkey around with measure and arrange - basically, instead of creating a single WrapPanel, you'll create something that puts these items into a StackPanel on each "row", each of which is its own shared-size scope. But actually measuring and arranging the heights of the timeline items is not something you need to worry about. You only need their widths (so that your logic can determine when to wrap). The Grid will take care of calculating the heights for you.

Resources