I've started developing a new application in WPF C#. The problem I'm having is regarding grid column definitions.
I have divided my Window into separate sections, using Grids' row and col definitions (see code below).
I have two rows. First is currently empty, second one contains a new grid, that is further divided into columns.
All grids are inside a border.
The weird behavior I'm getting, is this section of the code:
<Border BorderThickness="1" BorderBrush="#ffcd22" Grid.Column="1">
<Grid>
</Grid>
</Border>
<Border BorderThickness="1" BorderBrush="#ffcd22" Grid.Column="2">
<Grid>
</Grid>
</Border>
<Border BorderThickness="1" BorderBrush="#ffcd22" Grid.Column="3">
<Grid>
</Grid>
</Border>
The problem is, that the first "subgrid" actually corresponds to the
second column, The second and third both refer to the third column.
In other words, whenever I put any kind of control in the second subgrid (the one which has Grid.Column="2"), the control will appear in the third column for some reason.
I've been fiddling around with it, and can't seem to understand the behavior I'm getting.
Another example: I've put a control in the second column as following:
<Border BorderThickness="1" BorderBrush="#ffcd22" Grid.Column="2">
<Grid>
<TextBox Width="100" Height="50"></TextBox>
</Grid>
</Border>
The image below represents what I got:
Whole XAML code:
<Border BorderThickness="1" BorderBrush="#ffcd22" Margin="10,10,10,10">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border BorderThickness="1" BorderBrush="#ffcd22" Margin="-1,-1,-1,-1" Grid.Row="2">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<Border BorderThickness="1" BorderBrush="#ffcd22" Grid.Column="1">
<Grid>
</Grid>
</Border>
<Border BorderThickness="1" BorderBrush="#ffcd22" Grid.Column="2">
<Grid>
</Grid>
</Border>
<Border BorderThickness="1" BorderBrush="#ffcd22" Grid.Column="3">
<Grid>
</Grid>
</Border>
</Grid>
</Border>
</Grid>
The problem is that the column numeration starts from 0. You should change your code like this:
<Border BorderThickness="1" BorderBrush="#ffcd22" Grid.Column="0">
<Grid>
</Grid>
</Border>
<Border BorderThickness="1" BorderBrush="#ffcd22" Grid.Column="1">
<Grid>
</Grid>
</Border>
<Border BorderThickness="1" BorderBrush="#ffcd22" Grid.Column="2">
<Grid>
</Grid>
</Border>
Related
I want to build a customcontrol where expandable rows are added to grid. In order to match the columns of the expandable row, I added another grid as expander header and content. However, the columns are slightly tilted to the right (see picture). I think it is because of the header size?
How do I access the width of the togglebutton code, so I can change the columndefinitions accordingly?
Thanks!
There are a few ways to approach this.
One would be trying to find the width of that togglebutton yourself by looking at the control template and compensating - but this is unreliable as the template can change across .NET versions (and operating systems if I recall correctly) and is messy to implement anyway.
The second way is trying to programatically find the width and compensate that way, but that still requires digging into the control template (see issues above)
The third is to let the layout engine figure things out for you. You can do this by sharing the column width on columns 2-4, and setting the width of column 1 to "*". Doing this initially will yield undesired results however, because the Expander Header template has no way to set the HorizontalContentAlignment.
With a little of the above mentioned risk, you can fix that by digging around in the template via codebehind, as described here But its still not perfect yet.
Looks like there is a border or margin somewhere. Lets set the BorderThickness of the expander to 0.
UGH! Better - (the whitespace is gone), but there is still a gap between our grid (red with black border) and the green in .NET 4.5. I could not find the source of this gap in a reasonable amount of time, so I just set the Margin of the expander to 0,0,-1,0. This might need to be compensated for inside the expander depending on content, and brings up suppressed memories of CSS hacks (XAML was suppose to be better, wasn't it?)
End Result:
XAML:
<Window x:Class="Sandbox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="800" SnapsToDevicePixels="True">
<Window.Resources>
<DataTemplate x:Key="StretchedHeaderTemplate">
<Border HorizontalAlignment="Stretch" Loaded="Border_Loaded">
<ContentPresenter Content="{TemplateBinding Content}"/>
</Border>
</DataTemplate>
</Window.Resources>
<Grid Grid.IsSharedSizeScope="True" Margin="15">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="MainLeft"/>
<ColumnDefinition x:Name="MainRight"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Grid.Column="0" Background="AliceBlue">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="100" SharedSizeGroup="Col2"/>
<ColumnDefinition Width="100" SharedSizeGroup="Col3"/>
<ColumnDefinition Width="100" SharedSizeGroup="Col4"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" BorderBrush="Black" BorderThickness="1">
<TextBlock>Col1</TextBlock>
</Border>
<Border Grid.Column="1" BorderBrush="Black" BorderThickness="1">
<TextBlock>Col2</TextBlock>
</Border>
<Border Grid.Column="2" BorderBrush="Black" BorderThickness="1">
<TextBlock>Col3</TextBlock>
</Border>
<Border Grid.Column="3" BorderBrush="Black" BorderThickness="1">
<TextBlock>Col4</TextBlock>
</Border>
</Grid>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Center">January</TextBlock>
<TextBlock Grid.Column="1" HorizontalAlignment="Center">February</TextBlock>
<TextBlock Grid.Column="2" HorizontalAlignment="Center">March</TextBlock>
</Grid>
<StackPanel Grid.Column="0" Grid.Row="1">
<Expander HeaderTemplate="{StaticResource StretchedHeaderTemplate}" Background="LightGreen" BorderThickness="0" Margin="0,0,-1,0">
<Expander.Header>
<Grid HorizontalAlignment="Stretch" Background="LightCoral">
<Grid Grid.Column="0">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition SharedSizeGroup="Col2"/>
<ColumnDefinition SharedSizeGroup="Col3"/>
<ColumnDefinition SharedSizeGroup="Col4"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" BorderBrush="Black" BorderThickness="1">
<TextBlock>Record1</TextBlock>
</Border>
<Border Grid.Column="1" BorderBrush="Black" BorderThickness="1">
<TextBlock>02.05.2016</TextBlock>
</Border>
<Border Grid.Column="2" BorderBrush="Black" BorderThickness="1">
<TextBlock>05.05.2017</TextBlock>
</Border>
<Border Grid.Column="3" BorderBrush="Black" BorderThickness="1">
<TextBlock>340</TextBlock>
</Border>
</Grid>
</Grid>
</Expander.Header>
</Expander>
</StackPanel>
</Grid>
Code Behind:
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Border_Loaded(object sender, RoutedEventArgs e)
{
Border root = (Border)sender;
ContentPresenter presenter = (ContentPresenter)root.TemplatedParent;
presenter.HorizontalAlignment = HorizontalAlignment.Stretch;
}
}
Conclusion: This works, but you might want to consider overriding the control template for the Expander if you find any of it too messy.
I want to apply the following style to certain cells of my grid:
<Border BorderBrush="#808080" BorderThickness="1,1,0,0" Grid.Column="3" >
<Border BorderBrush="#404040" BorderThickness="1,1,0,0" Width="Auto">
<Border BorderBrush="#FFFFFF" BorderThickness="0,0,1,1" Width="Auto">
<Border BorderBrush="#DCE6F4" BorderThickness="0,0,1,1" Width="Auto">
</Border>
</Border>
</Border>
</Border>
Right now i specify the cell in the first line Grid.Colum="3". However to do this for all cells I have to copy paste this like 20 times. Is there any short way to apply my style to all controls or cells of my choice (for example cell 1, , 7, 9 or label1, label 9 and label10?
I am a newbie in wpf, please be gentle :)
Assuming you want to place labels inside the grid you could create a ControlTemplate and assign it to the labels you want with Template="{StaticResource BorderLabel}":
<Grid Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.Resources>
<ControlTemplate TargetType="Label" x:Key="BorderLabel">
<Border BorderBrush="#808080" BorderThickness="1,1,0,0" >
<Border BorderBrush="#404040" BorderThickness="1,1,0,0" Width="Auto">
<Border BorderBrush="#FFFFFF" BorderThickness="0,0,1,1" Width="Auto">
<Border BorderBrush="#DCE6F4" BorderThickness="0,0,1,1" Width="Auto">
<ContentControl Content="{TemplateBinding Content}" />
</Border>
</Border>
</Border>
</Border>
</ControlTemplate>
</Grid.Resources>
<Label Grid.Column="0" Content="MyText" />
<Label Grid.Column="1" Content="MyText" Template="{StaticResource BorderLabel}" />
</Grid>
And this is how it looks:
I want to make a popup which has a person's details on it. Each detail will be stacked vertically in the popup. I have two questions.
(1) How should I deal (graphically) with details which are not available?
(2) How to make the container around all the details dynamic so that its height is determined by the number of details available.
My first thought was the following;
<StackPanel Width="400"
Height="500">
<StackPanel x:Name="sp">
<Grid x:Name="spTelephone" Height="50">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="200" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Ellipse Fill="Blue"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
</Grid>
<Grid Grid.Column="1"
Margin="5,0,0,0">
<TextBlock Text="+Some Phone No."
VerticalAlignment="Center"
FontFamily="Verdana"/>
</Grid>
<Grid Grid.Column="2">
<Ellipse Fill="Blue"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
</Grid>
<Grid Grid.Column="3">
<Ellipse Fill="Blue"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
</Grid>
</Grid>
<Grid x:Name="spMobile" Height="50">
<!-- Repeat of above -->
</Grid>
<Grid x:Name="spEmail" Height="50">
<!-- Repeat of above -->
</Grid>
<!-- Further Grids -->
</StackPanel>
</StackPanel>
The idea being that if a detail is not available then I would set the Visibility property of the GRID to Visibility.Collapsed.
For example see my image with 3 details.
Then if a cell phone is not available it would look like this.
So how should I do this? I could for imagine using a ListView as well maybe as this would then take away the need to collapse the views. I could add each detail to an Item. But then how do I get the list view and its parent to resize its height?
Define datatemplate for item and use any items control to represent them.
Simple solution would be something like this:
Template
<DataTemplate x:Key="MyItemTemplate">
<Grid x:Name="spTelephone" Height="50">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="200" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Ellipse Fill="Blue"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
</Grid>
<Grid Grid.Column="1"
Margin="5,0,0,0">
<TextBlock Text="+Some Phone No."
VerticalAlignment="Center"
FontFamily="Verdana"/>
</Grid>
<Grid Grid.Column="2">
<Ellipse Fill="Blue"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
</Grid>
<Grid Grid.Column="3">
<Ellipse Fill="Blue"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
</Grid>
</Grid>
</DataTemplate>
Control
<Border BorderBrush="Black" BorderThickness="2" VerticalAlignment="Center" HorizontalAlignment="Center">
<ItemsControl ItemsSource="{Binding ItemsCollection}"
ItemTemplate="{StaticResource MyItemTemplate}"/>
</Border>
Of course you must fill collection from dataContext and for Text="+Some Phone No." also use data binding from current collection item.(Use DataContext={Binding} in template)
Border here is just to show that ItemsControl size changes according to collection-items count. Also ItemsControl can be replaced with any of it's descendants.
I want to change the alignment of my dockPanel, and I'm having some trouble. I'm relatively new to WPF, so that may explain it.
Anyways, here is the current layout:
<theme:bottomPanel DockPanel.Dock="Bottom" x:Name="bottomPanel" ClipToBounds="False" SnapsToDevicePixels="False" HorizontalAlignment="Center" Height="145" />
<theme:rightPanel DockPanel.Dock="Right" x:Name="rightPanel" ClipToBounds="False" SnapsToDevicePixels="False"/>
<theme:leftPanel DockPanel.Dock="Left" x:Name="leftPanel" ClipToBounds="False" SnapsToDevicePixels="False" />
<theme:MapPanel DockPanel.Dock="Top" x:Name="mapPanel" ClipToBounds="False" SnapsToDevicePixels="False" />
Visualized in Paint (lol) :
I would like to change the layout to something like the following:
Is this possible? If so, what approach would you recommend? Any guidance would be helpful! Thank you.
As an aside: is there any application that allows me to see my application layout as the app runs (i.e. add gridlines to each panel or something)?
Anyways, thanks!
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Border Background="Gray" Grid.ColumnSpan="3">
<TextBlock Text="Top Area"/>
</Border>
<Border Background="Magenta" Grid.Row="1" Height="200">
<TextBlock Text="Left Area"/>
</Border>
<Border Background="Red" Grid.Row="1" Grid.Column="1" Height="200">
<TextBlock Text="Bottom Area"/>
</Border>
<Border Background="Cyan" Grid.Column="2" Grid.RowSpan="2" Margin="0,200,0,0" Width="200">
<TextBlock Text="Right Area"/>
</Border>
</Grid>
There are known problems for setting up caliburn binding in DataTemplates.
In this answer EisenbergEffect suggests extracting Data Templates into a user control.
How can this be achieved?
In my user control I have lots of DataTemplates and ran into those problems. Conventions are not applied and I have to use "classical" Binding.
I could only imagine to extract the whole control with the DataTemplate, this would give me lots of smaller controls, but I see no way to only extract the DataTemplate.
Here is an example XAML
<Grid>
<Grid.Resources />
<Grid.RowDefinitions>
<RowDefinition Height="10*" />
<RowDefinition Height="2*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Border HorizontalAlignment="Stretch"
BorderBrush="Transparent"
BorderThickness="0">
<ScrollViewer HorizontalContentAlignment="Stretch"
Background="Yellow"
BorderBrush="Transparent"
BorderThickness="0"
CanContentScroll="True"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<!-- Conventions work here -->
<ListView x:Name="Computers"
HorizontalContentAlignment="Stretch"
Background="Red"
BorderThickness="0">
<ListView.ItemTemplate>
<DataTemplate>
<Border Background="Transparent"
BorderBrush="Transparent"
BorderThickness="0">
<ListView HorizontalContentAlignment="Stretch"
Background="Black"
ItemsSource="{Binding HardwareComponents}"> <!-- Conventions to not work here -->
<ListView.ItemTemplate>
<DataTemplate>
<Border Background="Aquamarine"
BorderBrush="DarkGray"
BorderThickness="1">
<Grid Background="Transparent" cal:Message.Attach="[Event MouseDown] = [Action Expand($dataContext)]" >
<Grid.RowDefinitions>
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<Border BorderBrush="Red" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<!-- Even more DataTemplates come here -->
</Border>
</Grid>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
</Border>
</Grid>