Wrapped Rows with Silverlight DataGrid - silverlight

I'm trying to style a Silverlight DataGrid so that the content displayed in the grid wraps. I want each grid row (and the grid header), to consist of TWO lines of cells, instead of one. This makes each row taller, but keeps all of the content visible on screen simultaneously, instead of having to scroll horizontally to see all of the fields. Here is a picture to help illustrate what I am going for:
Screenshot
(I don't have enough rep to post an image directly but the link above will show you an example screen shot)
I see the templates that let me customize how the different cells are styled, but I'm not seeing anything that will let me to control how those cells are displayed beside each other on the screen.

Your best bet here is going to be to abandon the datagrid and use a ListView instead, and inside the ListView you will want to show a UserControl of your own design. I did something similar for an application I built.
In your XAML for your ListView you will want to set the ItemContainerStyle and inside that you'll want to display your custom UserControl (in which you can use a Grid to setup the rows/colums and their spans). It basically looks like this:
<ListView
Name="_listView"
Grid.Row="0" Grid.Column="0"
SelectionMode="Single"
IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding SelectedAgent, Mode=TwoWay}"
ItemsSource="{Binding Agents, Mode=OneWay}"
GridViewColumnHeader.Click="ListView_Click"
DependencyProperties:ListBoxClickCommand.ClickCommand="{Binding ShowAgentDetailsCommand}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Border
Name="_border"
Padding="2"
CornerRadius="5"
SnapsToDevicePixels="true"
Background="Transparent">
<Controls:AgentStateControl></Controls:AgentStateControl>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="_border" Property="Background" Value="CornflowerBlue" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
The AgentStateControl is my custom control, and it has two rows, the second has a bigger span on the columns. You can create that control however you want.

Related

Expander.Content only applied to one

I am trying to apply style to multiple expanders which will have similar look and functionality. But the problem is that if I style Expander.Content only one of many will have content and the rest are all empty.
Minimal example:
<Style TargetType="Expander" BasedOn="{StaticResource {x:Type Expander}}">
<Setter Property="Header">
<Setter.Value>
Header
</Setter.Value>
</Setter>
<Setter Property="Content">
<Setter.Value>
<TextBlock Text="1"/>
</Setter.Value>
</Setter>
</Style>
<!-- .... -->
<Expander Grid.Row="0"/>
<Expander Grid.Row="1"/>
<Expander Grid.Row="2"/>
as you see only the second row has content (1) during design time. During run time only the last expander has content (1).
If I click on the first expander the content (1) from the third expander actually moved to the first expander.
Why is this happening? And how to fix it?
Styles only create one instance, which for visual elements can only be the child of a single parent. Set the ContentTemplate instead of the Content directly. (Templates just describe what is to be created by the control using it, so it can be shared.)

Create a visual template for grid

I am trying to create a visual template (saved in resource dictionary as xaml code) for a grid object, that I will apply to various grid objects created later in runtime.
I need a simple style with border and background.
What would be the best way of doing this?
Simple working examples would be greatly appreciated.
Ok, so, after searching for examples, I tried something like this:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="TestStyle">
<Setter Property="Background" Value="#FF873507" />
<Setter.Value>
<ControlTemplate>
<Grid>
<Border BorderThickness="7" CornerRadius="4">
<Border.BorderBrush>
<SolidColorBrush Color="#73B2F5"/>
</Border.BorderBrush>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Style>
</ResourceDictionary>
WPF doesn't really work like that... because the Grid class has no Template property, you cannot define a new ControlTemplate for it. The nearest thing that you can do is to create a UserControl with the UI elements that you want to use and then display the UserControl wherever you want to display those controls.
Alternatively, you could define your content inside a ControlTemplate if the inner controls will always be the same:
<ControlTemplate x:Key="StaticGrid">
<Grid>
<Border BorderThickness="7" CornerRadius="4">
<Border.BorderBrush>
<SolidColorBrush Color="#73B2F5"/>
</Border.BorderBrush>
<!--Add your inner elements here-->
</Border>
</Grid>
</ControlTemplate>
You could then display it like this:
<ContentControl Template="{StaticResource StaticGrid}" />
However, you wouldn't be able to add different inner elements using this method. If you used the UserControl method, you could potentially replace the word UserControl with Grid so that you were in fact extending the Grid class, but you still wouldn't be able to add different elements to it.
The best that you could do in a Style would be to set the Background property.
After more tries and frustrations, I found a much simpler solution, that worked for me.
Instead of trying to apply the style to the grid, I applied it to the border around the grid.
So, my dictionary looks like this:
<Style x:Key="TestStyle" TargetType="{x:Type Border}">
<Setter Property="Background" Value="#FFBDACA2" />
<Setter Property="BorderBrush" Value="#FFFF5E00" />
<Setter Property="CornerRadius" Value="30,30,30,30" />
<Setter Property="BorderThickness" Value="10" />
</Style>
And my main frame xaml:
<Border Style="{StaticResource TestStyle}" >
<Grid>
</Grid>
</Border>

WPF shared property

I have a question which I guess it's some basic knowledge which I missing in WPF.
I set default width (generix.XML) to Textbox with some Minim width for the textbox
<Style TargetType="{x:Type TextBox}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="MinWidth" Value="50"/>
</Style>
I have two deferent controls which holds text box. Both Textboxes has same width..
I which to add some property to one of the controls which will declare the width of the textbox, and will override its width declaration, in a way that the textbox will 'find' to this property.
here is some drawing describes my requirement:
Update:
I just figure out that I didn't described one more importing thing.
I Have some DataTemplate which uses the textbox. As I wrote above, I have two controls which have the same DataType (MyData) I also created DateTemplate to display MyData. I would like that each control will display the textbox (from the datatemple) with different width.
update 2:
here is some more code
1- The dataTemplate to my data where is using textbox
<DataTemplate DataType="{x:Type ml:MyData}">
<Border BorderBrush="Transparent" ClipToBounds="True" Style="{StaticResource errorBorder}">
<TextBox Text="{Binding MyText}"/>
</Border>
</DataTemplate>
2- the way I used the datatemplate which uses the Textbox.
<ContentPresenter Grid.Column="1" Margin="10,1,10,1" HorizontalAlignment="Left" Content="{Binding}" />
This contentPresentor is been displayed in two diffrent controls. and as I wrote before, I would like that each control will display the textbox in diferent width
It's look like I miss some basic knloage (attached proerty? logic/visual tree?).
Thanks, Leon
Good question, the main idea in DataTemplate is that you have specific graphical representation for some data. You can read more about it in MSDN.
If you want to customize your TextBox, and have it different properties inside different UserControls, you might want to use ControlTemplate.
The thing is that if you want to control properties of specific control (in this case TextBox with some border) you should use ControlTemplate.
Your XAML should look something like:
<ControlTemplate TargetType="{x:Type TextBox}">
<--! define the ControlTemplate here with some Width property-->
<ControlTemplate>
and the Control which use it will have TextBox (as you defined it, with Border):
<TextBox Grid.Column="1" Margin="10,1,10,1" HorizontalAlignment="Left" Content="{Binding}" Width="50"/>

WPF DataGrid Hyperlink Appearance and Behaviour

I am quite new to WPF, there is so much to learn and I think I'm getting there, slowly. I have a DataGrid which is used for display and user input, it's quite a tricky Grid as it is the main focus of the entire application. I have some columns that are read-only and I have used a CellStyle Setter to set KeyboardNavigation.IsTabStop to False to keep user input focused on the important columns and that works fine. I would like a couple of the read-only columns to be hyperlinks that show a tooltip and do not receive the focus, however I am struggling to write the XAML that will achieve all three requirements at the same time.
One of the columns is to indicate if the item on the row has any Notes. I have used the following XAML to display a HasNotes property in the cell in a DataGridTemplateColumn and on the Tooltip show the actual notes, in the Notes property:
<DataGridTemplateColumn x:Name="NotesColumn" Header="Notes">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding HasNotes, Mode=OneWay}">
<TextBlock.ToolTip>
<TextBlock Text="{Binding Notes}" MaxWidth="300" TextWrapping="Wrap" />
</TextBlock.ToolTip>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<Style>
<Setter Property="KeyboardNavigation.IsTabStop" Value="False"/>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
That works fine but I would like to make it a Hyperlink instead so the user can do something with the Notes when they click on the cell contents.
I have another column which is a DataGridHyperlinkColumn used to display a Unit of Measurement on a hyperlink and when clicked the user can change the unit. (The reason I have done it like this, rather than a ComboBox for example, is because as much as I want the user to be able to change the unit I want to make the interface such that it is a very deliberate act to change the unit, not something that can be done accidentally). The following XAML puts the Hyperlink column on for Unit
<DataGridHyperlinkColumn x:Name="ResultUnitLink" Binding="{Binding Path=Unit.Code}" Header="Unit" Width="Auto" IsReadOnly="True">
<DataGridHyperlinkColumn.CellStyle>
<Style>
<Setter Property="KeyboardNavigation.IsTabStop" Value="False"/>
</Style>
</DataGridHyperlinkColumn.CellStyle>
<DataGridHyperlinkColumn.ElementStyle>
<Style>
<EventSetter Event="Hyperlink.Click" Handler="ChangeUnit" />
</Style>
</DataGridHyperlinkColumn.ElementStyle>
</DataGridHyperlinkColumn>
One problem with the XAML for the Hyperlink column is that the IsTabStop = False doesn't appear to work, when tabbing through the Grid my hyperlink column still receives the focus, unlike the other columns where I've used a setter to change IsTabStop. If push comes to shove I could live with that but I'd rather not.
What I actually want from both those columns is an amalgamation of the two appearances/behaviours i.e. Columns where the data is displayed on a hyperlink, where TabStop = False and which display a tooltip of a different property when hovered over.
Can anyone help advise me how to get a column that achieves the following:
Hyperlink displaying one property
Tooltip displaying a different property
IsTabStop = False that actually works when used with a hyperlink
Thanks in advance to anyone who can help.
I've had issues with the Hyperlink in the past, so have this Style which I use for Labels or Buttons to make them look like Hyperlinks. Try making your column Template into a Button or a Label and applying this style.
<Style x:Key="ButtonAsLinkStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<TextBlock HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ContentPresenter ContentStringFormat="{TemplateBinding ContentStringFormat}" />
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="Blue" />
<Setter Property="Cursor" Value="Hand" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>

Styling a WPF layout grid background (of each cell, row, column)

I would like to know if there is any way to style a WPF layout grid's cells, rows and columns. I've been trying to find any information and the few mentions I've found have not been that informative.
I would like to style the grid to look like the one in the linked screenshot.
If the actual control does not support it, can I inherit it somehow and do it then? I am quite new to WPF so any help would be very appreciated.
One other thing, I know I can style each and every control within the grid, but it seems like overkill. I would like to have a grid that does it itself.
screenshot http://img21.imageshack.us/img21/2842/capturehz8.png
#Dan recommends WPF Unleashed, which I'm currently reading. Just this morning, I come across a section addressing your question.
Chapter 6, Page 161:
FAQ: How can I give Grid cells background colors, padding, and borders like I can with cells of a HTML Table?
There is no intrinsic mechanism to give Grid cells such properties, but you can simulate them pretty easily thanks to the fact that multiple elements can appear in any Grid cell. To give a cell a background color, you can simply plop in a Rectangle with the appropriate Fill, which stretches to fill the cell by default. To give a cell padding, you can use auto sizing and set the Margin on the appropriate child element. For borders, you can again use a Rectangle but give it an explicit Stroke of the appropriate color, or you can simply use a Border element instead.
Just be sure to add such Rectangles or Borders to the Grid before any of the other children (or explicitly mark them with the ZIndex attached property), so their Z order puts them behind the main content.
Btw, WPF Unleashed rocks. Its very well written, and the print in full color makes it even more easier to read.
Here's a quick (very rough sample) that you could hack around to get the format you want (if you're serious about working with WPF, you'll find Blend an enormous help in getting your layouts looking good):
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Style x:Key="CustomerDefinition" TargetType="TextBlock">
<Setter Property="Control.FontFamily" Value="Tahoma"/>
<Setter Property="Control.FontSize" Value="12"/>
<Setter Property="Control.Foreground" Value="Red"/>
</Style>
<Style TargetType="{x:Type Label}">
<Setter Property="Width" Value="100"/>
</Style>
<Style x:Key="{x:Type TextBox}" TargetType="{x:Type TextBox}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="MinWidth" Value="120"/>
<Setter Property="MinHeight" Value="20"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="Width" Value="200"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBoxBase}">
<Border
Name="Border"
Background="#FFEBE9E9"
BorderBrush="#FF8B8787"
BorderThickness="1"
CornerRadius="2"
Padding="3">
<ScrollViewer x:Name="PART_ContentHost" Margin="0"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background"
Value="#EEEEEE"/>
<Setter TargetName="Border" Property="BorderBrush"
Value="#EEEEEE"/>
<Setter Property="Foreground" Value="#888888"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<LinearGradientBrush x:Key="NormalBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0.0" Color="#FFF0EDED"/>
<GradientStop Offset="1.0" Color="#FFE1E0E0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
</Page.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="26"/>
<RowDefinition Height="23"/>
<RowDefinition Height="24"/>
<RowDefinition Height="24"/>
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<TextBlock
Grid.ColumnSpan="2"
Grid.Row="0"
Style="{StaticResource CustomerDefinition}"
Text="Customer Definition"/>
<Border
Grid.Column="0"
Grid.Row="1"
Background="#FFEBE9E9"
BorderBrush="#FF8B8787"
BorderThickness="1">
<StackPanel Background="{StaticResource NormalBrush}" Orientation="Horizontal">
<Label Content="Customer Code"/>
<TextBox Text="SMITHA 098 (normally I'd bind here)"/>
</StackPanel>
</Border>
<Border
Grid.Column="1"
Grid.Row="1"
Background="#FFEBE9E9"
BorderBrush="#FF8B8787"
BorderThickness="1">
<StackPanel Background="{StaticResource NormalBrush}" Orientation="Horizontal">
<Label Content="Customer Type"/>
<TextBox Text="PRIVATE INDIVIDUAL"/>
</StackPanel>
</Border>
</Grid> </Page>
The WPF Grid doesn't have visible cells as such. Think of them as invisible grid lines against which you can have child elements be aligned.
So, to style the grid's cells, you have to style the items that are aligned inside the grid.
It is confusing to think of the Grid as being anything like a WinForms DataGrid. I guess its closest WinForms equivalent is the TableLayout control.
Check out some 3rd party grid controls. I used the DevExpress one while it was in beta and found it pretty straightforward.
I would recommend using borders for your styling.
You could recreate that layout pretty easily by creating borders for each row and each column and set the rowspans and colspans accordingly.
You will have 5 borders with colspan 2, these borders will take care of your gradient backgrounds for each row and the borders along the top and bottom of each row. Then you will have 2 borders with rowspan 5 these will handle the column borders. Imagine that you are overlaying the borders to form the visual grid effect you are after.
For the header and outer border, just wrap the entire grid with a border and style as needed.
I would recommend storing your styles as resources so you can keep all your styling info in one place.
Take care to learn how the styling works because it is pretty powerful, but there is a learning curve as it is quite different to the way CSS works. I would recommend reading WPF Unleashed if you can.
I found this post when looking for method for setting margin (or padding) for DataGrid cells. My problem was solved thanks to example xaml code posted at (near the end) -- pretty minimalistic.
http://forums.silverlight.net/forums/p/16842/55997.aspx

Resources