Binding within a template - c#

I have the following ControlTemplate, as shown below, and I would like to avoid hard coding the hight and width of the image, instead I would like to bind the Height and width of the Image control
<Image Source="/Rotate.Pictures;component/Images/error.png"
Stretch="Uniform"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Height="14"
Width="14"/>
to the TextBlock's Text (TextBlock named "ErrorText") property path = "Height". Both Height and Width of the image should be bound to the Height value of the TextBlock's Text Height property
Does anyone know how I can accomplish this?
Template:
<Grid IsSharedSizeScope="True">
<Grid.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<StackPanel>
<AdornedElementPlaceholder>
<Border BorderBrush="Red" BorderThickness="2"/>
</AdornedElementPlaceholder>
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="/Rotate.Pictures;component/Images/error.png" Stretch="Uniform" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Height="14"
Width="14"/>
<TextBlock x:Name="ErrorText" Text="{Binding ErrorContent}" Foreground="Red"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>

Key to the answer is to reference past controls (control that the thread of execution already encountered in the "{Binding ElementName=ErrorText, Path=ActualHeight}"). So the solution uses a grid, then specify Grid.Column 1 before specifying Grid.Column 0 that references the ElementName in Grid.Column 1.
<Style TargetType="{x:Type TextBox}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<StackPanel>
<AdornedElementPlaceholder>
<Border BorderBrush="Red" BorderThickness="2"/>
</AdornedElementPlaceholder>
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock x:Name="ErrorText" Grid.Column="1" Text="{Binding ErrorContent}" Foreground="Red"/>
<Image Grid.Column="0" Source="/Rotate.Pictures;component/Images/error.png"
Height="{Binding ElementName=ErrorText, Path=ActualHeight}"
Width="{Binding ElementName=ErrorText, Path=ActualHeight}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Related

Binding DataGridTemplateColumn in UserControl.Resources

I am currently trying to write a small calendar program in C# WPF.
For the datagrid I have written a userControl.
This works like I want it to work. I will still need to update the optics but for now it is good.
The problem is the code of the DataGridTextColums.. It is all redundant.
So if I want to change something I need to change it everywhere.
<DataGrid x:Name="datagrid"
CanUserAddRows="False"
CanUserDeleteRows="False"
CanUserResizeColumns="False"
CanUserReorderColumns="False"
CanUserResizeRows="False"
CanUserSortColumns="False"
AutoGenerateColumns="False"
SelectionUnit="Cell"
SelectionMode="Extended"
HeadersVisibility="Column"
Background="Transparent"
BorderBrush="Transparent"
ItemsSource="{Binding DataGridSource.DataGridList, RelativeSource={RelativeSource AncestorType=UserControl}}">
<DataGrid.Columns>
<DataGridTextColumn Header="CW" Width="*" IsReadOnly="True" Binding="{Binding CwCell.Text}">
<DataGridTextColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Background" Value="{Binding CwCell.BackColor}"/>
<Setter Property="BorderBrush" Value="{Binding CwCell.BorderColor}"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderBrush" Value="OrangeRed"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTemplateColumn Header="MO" Width="*" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border>
<StackPanel Orientation="Horizontal" Background="Transparent">
<TextBlock Text="{Binding MondayCell.Text}" Margin="5,0,0,0" Width="18"/>
<ItemsControl ItemsSource="{Binding Path=MondayCell.Addons}" Margin="0,0,7,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" MaxHeight="20"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Width="4" Height="4" Margin="0,1,1,1" Fill="{Binding Color}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Background" Value="{Binding MondayCell.BackColor}"/>
<Setter Property="BorderBrush" Value="{Binding MondayCell.BorderColor}"/>
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip BorderThickness="0" Background="Transparent">
<Grid>
<Border Background="White" BorderBrush="Black" BorderThickness="1">
<StackPanel Orientation="Vertical" DataContext="{Binding MondayCell}">
<TextBlock Text="{Binding AppointmentName}"
Background="White" Width="auto" Margin="5,5,5,1"
TextWrapping="Wrap"
FontWeight="Bold"/>
<Border BorderBrush="Silver" BorderThickness="0,1,0,0" Margin="0,1,0,0" />
<TextBlock Text="{Binding AppointmentDescr}"
Background="White" Margin="5,1,5,5"
TextWrapping="Wrap"/>
<Border BorderBrush="Silver" BorderThickness="0,1,0,0" Margin="0,1,0,0" />
<ItemsControl ItemsSource="{Binding Path=Addons}" Margin="0,0,7,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical">
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Ellipse Width="4" Height="4" Fill="{Binding Color}" Margin="5,0,5,0"/>
<Border BorderBrush="Silver" BorderThickness="1,0,0,0" Margin="0,0,0,0"/>
<TextBlock Text="{Binding Name}" Margin="5,0,0,0"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</Grid>
</ToolTip>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderBrush" Value="OrangeRed"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="DI" Width="*" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border>
<StackPanel Orientation="Horizontal" Background="Transparent">
<TextBlock Text="{Binding TuesdayCell.Text}" Margin="5,0,0,0" Width="18"/>
<ItemsControl ItemsSource="{Binding Path=TuesdayCell.Addons}" Margin="0,0,7,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" MaxHeight="20"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Width="4" Height="4" Margin="0,1,1,1" Fill="{Binding Color}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Background" Value="{Binding TuesdayCell.BackColor}"/>
<Setter Property="BorderBrush" Value="{Binding TuesdayCell.BorderColor}"/>
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip BorderThickness="0" Background="Transparent">
<Grid>
<Border Background="White" BorderBrush="Black" BorderThickness="1">
<StackPanel Orientation="Vertical" DataContext="{Binding TuesdayCell}">
<TextBlock Text="{Binding AppointmentName}"
Background="White" Width="auto" Margin="5,5,5,1"
TextWrapping="Wrap"
FontWeight="Bold"/>
<Border BorderBrush="Silver" BorderThickness="0,1,0,0" Margin="0,1,0,0" />
<TextBlock Text="{Binding AppointmentDescr}"
Background="White" Margin="5,1,5,5"
TextWrapping="Wrap"/>
<Border BorderBrush="Silver" BorderThickness="0,1,0,0" Margin="0,1,0,0" />
<ItemsControl ItemsSource="{Binding Path=Addons}" Margin="0,0,7,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical">
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Ellipse Width="4" Height="4" Fill="{Binding Color}" Margin="5,0,5,0"/>
<Border BorderBrush="Silver" BorderThickness="1,0,0,0" Margin="0,0,0,0"/>
<TextBlock Text="{Binding Name}" Margin="5,0,0,0"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</Grid>
</ToolTip>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderBrush" Value="OrangeRed"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
<!--same for wednesdayCell to sundayCell-->
</DataGrid.Columns>
</DataGrid>
So as you can see each DataGridTemplateColumn binds to a different Cell (Monday to Sunday).
I tried to create a template out of this. If i keep "MondayCell" in the template (like in the Code below), it works. But obviously I cannot use any other source of data except "MondayCell" then.
See:
<UserControl.Resources>
<DataTemplate x:Key="MyCellTemplate">
<Border>
<StackPanel Orientation="Horizontal" Background="Transparent">
<TextBlock Text="{Binding MondayCell.Text}" Margin="5,0,0,0" Width="18"/>
<ItemsControl ItemsSource="{Binding Path=MondayCell.Addons}" Margin="0,0,7,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" MaxHeight="20"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Width="4" Height="4" Margin="0,1,1,1" Fill="{Binding Color}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</DataTemplate>
<Style TargetType="{x:Type DataGridCell}" x:Key="MyCellStyle">
<Setter Property="Background" Value="{Binding MondayCell.BackColor}"/>
<Setter Property="BorderBrush" Value="{Binding MondayCell.BorderColor}"/>
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip BorderThickness="0" Background="Transparent">
<Grid>
<Border Background="White" BorderBrush="Black" BorderThickness="1">
<StackPanel Orientation="Vertical" DataContext="{Binding MondayCell}">
<TextBlock Text="{Binding AppointmentName}"
Background="White" Width="auto" Margin="5,5,5,1"
TextWrapping="Wrap"
FontWeight="Bold"/>
<Border BorderBrush="Silver" BorderThickness="0,1,0,0" Margin="0,1,0,0" />
<TextBlock Text="{Binding AppointmentDescr}"
Background="White" Margin="5,1,5,5"
TextWrapping="Wrap"/>
<Border BorderBrush="Silver" BorderThickness="0,1,0,0" Margin="0,1,0,0" />
<ItemsControl ItemsSource="{Binding Path=Addons}" Margin="0,0,7,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical">
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Ellipse Width="4" Height="4" Fill="{Binding Color}" Margin="5,0,5,0"/>
<Border BorderBrush="Silver" BorderThickness="1,0,0,0" Margin="0,0,0,0"/>
<TextBlock Text="{Binding Name}" Margin="5,0,0,0"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</Grid>
</ToolTip>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderBrush" Value="OrangeRed"/>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
Usage in the Datagrid: This works, but only shows the data from MondayCell.
<DataGridTemplateColumn Header="MO" Width="*" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<StaticResource ResourceKey="MyCellTemplate"/>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<StaticResource ResourceKey="MyCellStyle"/>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
How I want to use it, but doesn't work like this:
Any help is appreciated.
For now I keep it redundant, but I would rather use a template so I only need to change 1 piece of code instead of 7.
Thank you for your help!
I would like to present a solution that is based on using a UserControl:
<DataGridTemplateColumn >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<local:StandardColumn Column="{Binding MondayCell}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<local:StandardColumn Column="{Binding TuesdayCell}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
The StandardColumn implementation , for simplicity , can be as following:
<UserControl x:Class="Problem8.StandardColumn"
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"
xmlns:local="clr-namespace:Problem8"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" Name="Parent">
<StackPanel>
<TextBlock Text="{Binding ElementName=Parent,Path=Column}"/>
</StackPanel>
</UserControl>
In this userControl we have a dependency property called Column :
public partial class StandardColumn : UserControl
{
public StandardColumn()
{
InitializeComponent();
}
public static readonly DependencyProperty ColumnProperty =
DependencyProperty.Register("Column", typeof(object), typeof(StandardColumn));
public object Column
{
get { return (object)GetValue(ColumnProperty); }
set { SetValue(ColumnProperty, value); }
}
}
We can also make it even more simple by using the DataContext instead of the Column dependency property.
You could build your columns dynamically using a base string out a txt file and use xamlreader.Parse or persist to disk and then use xamlreader.load.
I answered a similar question a while back but I cannot find the answer.
Create a template as a txt file with placeholders for the parts you want to substitute. Here is the example I use in a sample I wrote:
<?xml version="1.0" encoding="utf-8" ?>
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="xxMMMxx" TextAlignment="Center" Grid.ColumnSpan="2"/>
<TextBlock Text="Units" Margin="2,0,2,0" Grid.Row="1"/>
<TextBlock Text="Value" Margin="2,0,2,0" Grid.Row="1" Grid.Column="2" />
</Grid>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding MonthTotals[xxNumxx].Products}" Margin="2,0,2,0" TextAlignment="Right"/>
<TextBlock Text="{Binding MonthTotals[xxNumxx].Total}" Margin="2,0,2,0" TextAlignment="Right" Grid.Column="1"/>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Make that content, copy if newer and you will get a txt file next to your exe you can read in.
In this I have a dynamic datagrid as another txt file as well, but that is not totally necessary.
Here's my code builds and adds columns.
You could just work with the txt file as a string and do string substitution. This shows manipulating it as xml which has the potential for you to insert xelements etc. It is setting attributes whilst you can maybe forget that part and just do the string substitution, xamlreader.parse into a datagrid column and add to the columns collection.
It is substituting month numbers in the binding for a range of months.
If you consider a rolling last n month financial report, this is the general idea. Last month would be 3 now in april. 4 when you run in may.
private void Button_Click(object sender, RoutedEventArgs e)
{
// Get the datagrid shell
XElement xdg = GetXElement(#"pack://application:,,,/dg.txt");
XElement cols = xdg.Descendants().First(); // Column list
// Get the column template
XElement col = GetXElement(#"pack://application:,,,/col.txt");
DateTime mnth = DateTime.Now.AddMonths(-6);
for (int i = 0; i < 6; i++)
{
DateTime dat = mnth.AddMonths(i);
XElement el = new XElement(col);
// Month in mmm format in header
var mnthEl = el.Descendants("TextBlock")
.Single(x => x.Attribute("Text").Value.ToString() == "xxMMMxx");
mnthEl.SetAttributeValue("Text", dat.ToString("MMM"));
string monthNo = dat.AddMonths(-1).Month.ToString();
// Month as index for the product
var prodEl = el.Descendants("TextBlock")
.Single(x => x.Attribute("Text").Value == "{Binding MonthTotals[xxNumxx].Products}");
prodEl.SetAttributeValue("Text",
"{Binding MonthTotals[" + monthNo + "].Products}");
// Month as index for the total
var prodTot = el.Descendants("TextBlock")
.Single(x => x.Attribute("Text").Value == "{Binding MonthTotals[xxNumxx].Total}");
prodTot.SetAttributeValue("Text",
"{Binding MonthTotals[" + monthNo + "].Total}");
cols.Add(el);
}
string dgString = xdg.ToString();
ParserContext context = new ParserContext();
context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
DataGrid dg = (DataGrid)XamlReader.Parse(dgString, context);
Root.Children.Add(dg);
}
private XElement GetXElement(string uri)
{
XDocument xmlDoc = new XDocument();
var xmltxt = Application.GetContentStream(new Uri(uri));
string elfull = new StreamReader(xmltxt.Stream).ReadToEnd();
xmlDoc = XDocument.Parse(elfull);
return xmlDoc.Root;
}
}
You could potentially build out your entire year view using this sort of approach. Build it as xml or a string. Save to disk. xamlreader.load() it back in as controls off disk.
A similar string manipulation based approach would be to build your control as text. Save as a datatemplate in a resource dictionary. You can load such an uncompiled resource dictionary off disk then and just build once a year. You could build centrally in a small utility app intended just for the purpose and distribute to clients.
This is my second solution. I believe that the selection of the DataGrid as a base have created this complexity. Alternatively we can consider more basic controls.
I am drafting the solution:
The MonthView user control may look as following:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<local:HeaderView Grid.Row="0"/>
<ItemsControl ItemsSource="{Binding Weeks}" Grid.Row="1" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:WeekView/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
The WeekView user control may look as following:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<local:DayView DataContext="{Binding CwCell}" Grid.Column="0"/>
<local:DayView DataContext="{Binding MondayCell}" Grid.Column="1"/>
<local:DayView DataContext="{Binding TuesdayCell}" Grid.Column="2"/>
<local:DayView DataContext="{Binding WednesdayCell}" Grid.Column="3"/>
<local:DayView DataContext="{Binding ThursdayCell}" Grid.Column="4"/>
<local:DayView DataContext="{Binding FridayCell}" Grid.Column="5"/>
<local:DayView DataContext="{Binding FridayCell}" Grid.Column="6"/>
<local:DayView DataContext="{Binding SaturdayCell}" Grid.Column="7"/>
<local:DayView DataContext="{Binding SundayCell}" Grid.Column="8"/>
</Grid>
The DayView user control may look as following:
<Border BorderBrush="Black" BorderThickness="1">
<TextBlock Text="{Binding Text}" Width="20" Height="20" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
The HeaderView user control may look as following:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<local:ColumnHeaderView DataContext="CW" Grid.Column="0" />
<local:ColumnHeaderView DataContext="MO" Grid.Column="1" />
<local:ColumnHeaderView DataContext="TU" Grid.Column="2" />
<local:ColumnHeaderView DataContext="WE" Grid.Column="3" />
<local:ColumnHeaderView DataContext="TH" Grid.Column="4" />
<local:ColumnHeaderView DataContext="FR" Grid.Column="5" />
<local:ColumnHeaderView DataContext="SA" Grid.Column="6" />
<local:ColumnHeaderView DataContext="SU" Grid.Column="7" />
</Grid>
The ColumnHeaderView user control may look as following:
<Border BorderBrush="Black" BorderThickness="1">
<TextBlock Text="{Binding }" Width="20" Height="15" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>

XAML : expand expander when an item in the group is selected

Is it possible for a expander to check for the IsExpanded Property if an item inside the group of the expander is selected then this expander is expanded so IsExpanded will be true? Because if i set it to true by default all expanders will be expanded at that's not the goal.
<controls:CommandListBox Grid.IsSharedSizeScope="True"
Visibility="{Binding IsComponentOrSystemPropertySearch, Converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Column="2"
HorizontalAlignment="Stretch"
SelectedItem="{Binding SelectedResult}"
ToolbarItems="{Binding ToolBarItems}"
ItemsSource="{Binding SearchResults, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.Resources>
<ResourceDictionary>
<Style x:Key="GroupHeaderStyle"
TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander x:Name="exp" IsExpanded="False" Margin="0,0,0,30" >
<Expander.Header >
<TextBlock Text="{Binding Path=Name}" FontSize="18" Padding="0" Margin="0"/>
</Expander.Header>
<Grid Margin="20 0 0 0" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ContentPresenter Grid.Column="0"
Grid.Row="0"
Content="{Binding Path=Items[0].DisplayRepresentation.Header}"/>
<ItemsPresenter Grid.Column="0"
Grid.Row="1"/>
</Grid>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</ItemsControl.Resources>
<ItemsControl.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource GroupHeaderStyle}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</ItemsControl.GroupStyle>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:DeluxePropertySearchResult}">
<ContentPresenter Content="{Binding DisplayRepresentation}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</controls:CommandListBox>

Defining a border for ListView's item Template

Here is the XAML code for the ListView.
<ListView VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
x:Name="listView1">
<ListView.ItemTemplate>
<DataTemplate>
<Border HorizontalAlignment="Stretch"
BorderThickness="1"
BorderBrush="LightBlue">
<StackPanel Orientation="Vertical">
<Label BorderThickness="0,0,0,1"
BorderBrush="#BABABA"
HorizontalAlignment="Stretch">Keywords</Label>
<TextBlock Text="{Binding keywords}"
Foreground="#3399AA"
HorizontalAlignment="Stretch" />
<Label BorderThickness="0,0,0,1"
BorderBrush="#BABABA">Content</Label>
<TextBlock MaxHeight="50"
Text="{Binding contentAsString}"
TextWrapping="Wrap"
Foreground="Black"
Height="auto"
Width="auto" />
</StackPanel>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And here is how it looks
No matter what I've tried I couldn't create a border for the whole listview item. How can we do that?
Try with Stretch
<ListView>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
. . .
<Viewbox Stretch="Fill"/>

XAML Listbox alignment issue

I have a Windows Phone 8 page with Country Names on left and ISD codes on right. I want to align the country name to the extreme left and ISD code to the extreme right of the screen.
For this, I wrote the following XAML
<Grid x:Name="LayoutRoot" Background="Transparent">
<ListBox ItemsSource="{Binding IsdCodes}" HorizontalAlignment="Stretch" Background="Blue">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch" Background="Yellow" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" HorizontalAlignment="Stretch" Text="{Binding Key}" />
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" Text="{Binding Value}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
But the output I am getting is as follows :
As I gave the grid column widths as 3* and *, I expected first column to occupy 75% of the width of the screen on left and 2nd column to occupy 25% of the width of the screen on the right. But I do see that listbox item still doesn't occupy the entire screen width (Assumed from the yellow background).
Where did I go wrong?
Try setting HorizontalContentAlignment for ListBoxItem to Stretch:
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
This is because the DataTemplate is rendered in a ContentPresenter, which is not stretched in the ListBoxItem. You need to redefine the template for the ListBoxItem:
...
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
<ContentPresenter HorizontalAlignment="Stretch" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
...
As you know width of screen is 480 you could assign it 360 and 120
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch" Background="Yellow" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="360"/>
<ColumnDefinition Width="120" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" HorizontalAlignment="Stretch" Text="{Binding Key}" />
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" Text="{Binding Value}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
This would help you, set width of grid inside listbox datatemplete
<Grid x:Name="LayoutRoot" Background="Transparent">
<ListBox ItemsSource="{Binding IsdCodes}" HorizontalAlignment="Stretch" Background="Blue">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Left" Background="Yellow" ShowGridLines="True" Width="460">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" HorizontalAlignment="Stretch" Text="{Binding Key}" />
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" Text="{Binding Value}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>

WPF ListBox can not set BackgroundColor

I have a problem, that I can not set the background color of my ListBox-Control. I create a ItemsControl template and DataTemplates:
<Style TargetType="ItemsControl" x:Key="LogViewerStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<ScrollViewer CanContentScroll="True">
<ItemsPresenter SnapsToDevicePixels="True" />
</ScrollViewer>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<DataTemplate DataType="{x:Type local:LogEntry}">
<Grid IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="Index" Width="Auto"/>
<ColumnDefinition SharedSizeGroup="Date" Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Index}" Grid.Column="0" FontWeight="Normal" Margin="2,0,2,0" Foreground="{Binding Path=LineNumbersColor, ElementName=LogViewerProperty}" Cursor="RightArrow.cur" TextAlignment="Right" />
<TextBlock Text="{Binding DateTime}" Grid.Column="1" FontWeight="Bold" Margin="0,0,5,0" />
<TextBlock Text="{Binding Message}" Grid.Column="2" TextWrapping="{Binding Path=WordWrapping, ElementName=LogViewerProperty, Converter={StaticResource BoolToTextWrap}}" />
</Grid>
</DataTemplate>
When I try to give my ListBox a BackgroundColor nothing happens:
<ListBox ItemsSource="{Binding}" x:Name="LogViewer" Background="Cornsilk" Style="{StaticResource LogViewerStyle}">
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer CanContentScroll="True" Padding="{TemplateBinding Padding}" HorizontalScrollBarVisibility="{Binding Path=WordWrapping, ElementName=LogViewerProperty, Converter={StaticResource BoolToScrollbarVisibility}}" VerticalScrollBarVisibility="{Binding Path=VerticalScrollbarVisible, ElementName=LogViewerProperty}">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsItemsHost="True">
</VirtualizingStackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ListBox>
At the moment I don't have clue why. Can anybody give me a hint? Thanks!
You apply a style to ListBox with the key LogViewerStyle which futhermore defines a template but then you create another template for ListBox implicitly.
Why? That is not wpf's usual bread. Its not making sence, is it?
Remove one of them please.
Though to answer your question you will have to tell your ScrollViewer to listen to the Background of the ListBox.
Take a look at this:
<Style TargetType="ListBox" x:Key="MyListBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Background="{TemplateBinding Background}">
<ScrollViewer CanContentScroll="True">
<ItemsPresenter SnapsToDevicePixels="True" />
</ScrollViewer>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
And then just set the style on the ListBox.
<ListBox Style="{StaticResource MyListBox}" />
Take a look how it tells Grid to have its Background same as ListBox will have.
Setting Background="{TemplateBinding Background}" applies background for me
<ListBox ItemsSource="{Binding}" Width="100" x:Name="LogViewer" Background="Red" Style="{StaticResource LogViewerStyle}">
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer CanContentScroll="True" Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}" HorizontalScrollBarVisibility="{Binding Path=WordWrapping, ElementName=LogViewerProperty, Converter={StaticResource BoolToScrollbarVisibility}}" VerticalScrollBarVisibility="{Binding Path=VerticalScrollbarVisible, ElementName=LogViewerProperty}">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsItemsHost="True">
</VirtualizingStackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ListBox>

Categories