Grid and ItemsControl.ItemContainerStyle in WIndows Phone - silverlight

I've got a serious problem and i can't solve it. There is the following code what perfectly works in WPF:
<ItemsControl Grid.Row="1" ItemsSource="{Binding GameFields}" HorizontalAlignment="Stretch">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="7" Columns="7" Margin="20" HorizontalAlignment="Center" VerticalAlignment="Center" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding SingleStepCommand}" CommandParameter="{Binding Index}" Visibility="{Binding Visible}" Background="Transparent"
Margin="10" BorderBrush="Transparent" BorderThickness="0">
<Button.Content>
<Image Source="{Binding IconPath}" Stretch="Fill" />
</Button.Content>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Row" Value="{Binding X}" />
<Setter Property="Grid.Column" Value="{Binding Y}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
And a try to implement in Windows Phone(7.1). But all elements of the itemspaneltemplate grid are on each other, i mean on the same X and Y position. Here's what i've tried:
<ItemsControl x:Name="ContentSource" Grid.Row="1" Margin="12,0,12,0" ItemsSource="{Binding GameFields}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RenderTransform>
<TransformGroup>
<TranslateTransform X="{Binding X}" Y="{Binding Y}" />
</TransformGroup>
</Grid.RenderTransform>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding SingleStepCommand}" CommandParameter="{Binding Index}" Visibility="{Binding Visible}" Grid.Row="{Binding X}"
Grid.Column="{Binding Y}">
<Button.Content>
<Image Source="{Binding IconPath}" Stretch="Fill" />
</Button.Content>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
<!--ItemsControl.Resources>
<Style TargetType="ContentPresenter">
<Setter Property="Grid.Row" Value="17" />
<Setter Property="Grid.Column" Value="17" />
</Style>
</ItemsControl.Resources-->
</ItemsControl>
3 different way and none of them works. (Resources, TranslateTransform and Button grid.row binding). Do you have any suggestion what im doing wrong or what should i use?
I have to use MVVM strictly, so there's no code behind. Any advice will get thanks and sorry for my english :)

You have got the right idea - you do need to set the Grid.Row and Grid.Column properties on the ContentPresenter. The easiest way to do this is with your own Attached Properties for each.
Something like this:
public class ItemsGridLayout
{
public static int GetGridRow(DependencyObject obj)
{
return (int)obj.GetValue(GridRowProperty);
}
public static void SetGridRow(DependencyObject obj, int value)
{
obj.SetValue(GridRowProperty, value);
}
// Using a DependencyProperty as the backing store for GridRow. This enables animation, styling, binding, etc...
public static readonly DependencyProperty GridRowProperty =
DependencyProperty.RegisterAttached("GridRow", typeof(int), typeof(FrameworkElement), new PropertyMetadata(0, (s, e) =>
{
var presenter = GetItemsPresenter(s);
if (presenter != null)
{
Grid.SetRow(presenter, GetGridRow(s));
}
}));
public static int GetGridColumn(DependencyObject obj)
{
return (int)obj.GetValue(GridColumnProperty);
}
public static void SetGridColumn(DependencyObject obj, int value)
{
obj.SetValue(GridColumnProperty, value);
}
// Using a DependencyProperty as the backing store for GridColumn. This enables animation, styling, binding, etc...
public static readonly DependencyProperty GridColumnProperty =
DependencyProperty.RegisterAttached("GridColumn", typeof(int), typeof(FrameworkElement), new PropertyMetadata(0, (s, e) =>
{
var presenter = GetItemsPresenter(s);
if (presenter != null)
{
Grid.SetColumn(presenter, GetGridColumn(s));
}
}));
static FrameworkElement GetItemsPresenter(DependencyObject target)
{
while (target != null)
{
if (target is ContentPresenter)
{
return target as FrameworkElement;
}
target = VisualTreeHelper.GetParent(target);
}
return null;
}
}
Then in XAML it's used like this:
<ItemsControl>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button local:ItemsGridLayout.GridRow="{Binding X}"
local:ItemsGridLayout.GridColumn="{Binding Y}"

I ran into the very same problem today. Learning Silverlight after WPF, I didn't expect that this wouldn't work.
After a few more searches to avoid this kind of workaround, I tried to add a Style resource for the ContentPresenter and it worked like a charm in Silverlight 5.
<ItemsControl ItemsSource="{Binding Source={StaticResource CVM}, Path=PagedItems}">
<ItemsControl.Resources>
<Style TargetType="ContentPresenter">
<Setter Property="Grid.Column" Value="{Binding OffsetX}"/>
<Setter Property="Grid.Row" Value="{Binding OffsetY}"/>
</Style>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
...
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
...
<RowDefinition/>
</Grid.RowDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>

Related

Bizarre WPF Template Rerendering

My WPF application is employing the MVVM pattern, where the views are discovered using WPFs type-based DataTemplate mechanism.
I have one View that contains a ListBox, and the DataTemplate for the ViewModel type in the ListBox is in a Resource on the Grid that contains the ListBox.
In this DataTemplate, I have a custom Button class that has a DependencyProperty that is bound to a string property on the underlying ViewModel. When the Button is clicked, code-behind in the custom Button class gets the value out of the DependencyProperty and passes it in to a modal dialog, gets the edited value back from the dialog and updates the DependencyProperty (which then flows, through binding, back into the ViewModel). This whole process works fine.
However, the very first time this happens, something in the rendering of the dialog causes WPF to do something which results in the items in the ListBox being re-rendered. As a result of this, the actual Button that was clicked is detached from the Visual Tree, and the object being bound to is "disconnected". This only happens the very first time the dialog is evoked during the run of the application. Once it happens, everything is fine until you restart the application.
I'm at a loss. My best guess (based on the call stack for the constructor of my custom Button) is that something is causing WPF to recompile the resources for my application (or, at least, this one View), but I can't imagine what, nor how to prevent it (or force it to happen during startup).
Any suggestions would be awesome. Thanks!
David Mullin
IMA Technologies
Edited: Here's an attempt to show what the code looks like (boiler plate code omitted)
<Grid>
<Grid.Resources>
<DataTemplate DataType="{x:Type ct:RecordDisplayDataSourceAuthoringViewModel}">
<ctConfigControls:SetInfoButton Info="{Binding AutoNewSetInfoXml.Value}" Content="Set Info" />
</DataTemplate>
</Grid.Resources>
<!-- The DataSources property contains a list of RecordDisplayDataSourceAuthoringViewModel -->
<ListBox Grid.Row="1" ItemsSource="{Binding Path=DataSources}" />
</Grid>
public class SetInfoButton : Button
{
public static readonly DependencyProperty InfoProperty = DependencyProperty.Register("Info", typeof(string), typeof(SetInfoButton),
new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public string Info
{
get { return (string)GetValue(InfoProperty); }
set { SetValue(InfoProperty, value); }
}
public SetInfoButton()
{
Click += new RoutedEventHandler(SetInfoButton_Click);
Focusable = false;
}
void SetInfoButton_Click(object sender, RoutedEventArgs e)
{
string info = Info;
if (SetInfoDialog.Show(VisualTreeHelperEx.FindVisualAncestor<Window>(this), ref info) == true)
{
Info = info;
}
}
}
public partial class SetInfoDialog : DialogWindow, IDesignerDataSource
{
public static bool Show(Window parent, ref string info)
{
SetInfoDialog dlg = new SetInfoDialog(info);
dlg.Owner = parent;
if (dlg.ShowDialog() == true)
{
info = dlg.RawInfo;
return true;
}
return false;
}
public SetInfoDialog(string rawInfo)
{
//...
}
}
<ct:DialogWindow x:Class="CaseTrakker.Windows.Dialogs.SetInfoDialog">
<ct:DialogWindow.Buttons>
<ct:ImageButton Image="{DynamicResource {x:Static ct:Common.OkImageKey}}" Content="_Ok" Click="Ok_Click" />
<ct:ImageButton Image="{DynamicResource {x:Static ct:Common.CancelImageKey}}" Content="_Cancel" Click="Cancel_Click" IsCancel="True" />
</ct:DialogWindow.Buttons>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Grid.Column="0" Visibility="{Binding Path=HideObjectSelectorControls, Converter={StaticResource InvertedBoolToVisibilityConverter}}" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0">System Object</Label>
<ct:SystemObjectComboBox Grid.Row="0" Grid.Column="1" CreateOnly="True" SelectedValue="{Binding Path=SystemObjectNumber}" />
<Label Grid.Row="1" Grid.Column="0">Type</Label>
<ctConfigControls:TemplateComboBox Grid.Row="1" Grid.Column="1"
SystemObject="{Binding Path=SystemObjectNumber, Converter={StaticResource IntToStandardSystemObjectConverter}}"
SelectedValue="{Binding Path=TemplateId}" />
</Grid>
<Button Grid.Row="0" Grid.Column="1" Click="Import_Click">Import</Button>
<Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Vertical" Margin="4,8,4,4"
Visibility="{Binding Path=DisplayText, Converter={StaticResource EmptyToVisibilityConverter}}">
<Label FontWeight="Bold">Notes</Label>
<TextBox Text="{Binding Path=DisplayText, Mode=OneWay}" IsReadOnly="True"/>
</StackPanel>
<ctConfigDesigner:DataDesigner x:Name="Designer" Grid.Column="1" Loaded="DataDesigner_Loaded" />
</Grid>
</Grid>
</ct:DialogWindow>
<Style x:Key="DialogWindowStyle" TargetType="{x:Type ctWindows:DialogWindow}" BasedOn="{StaticResource {x:Type Window}}">
<Setter Property="Background" Value="{DynamicResource {x:Static ctThemes:Common.StandardWindowBackgroundBrushKey}}" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Grid.LayoutTransform>
<ScaleTransform x:Name="ZoomFrame"
ScaleX="{Binding Path=ZoomValue, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}"
ScaleY="{Binding Path=ZoomValue, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}"/>
</Grid.LayoutTransform>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Row="0" Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.Row="0" Grid.Column="0" Height="35" Width="35"
Visibility="{Binding Path=HasTitleImage, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}, Converter={StaticResource BoolToVisibilityConverter}}"
Source="{Binding Path=TitleImage, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}" />
<Label Grid.Row="0" Grid.Column="1" Content="{Binding Path=Title, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}"
Style="{DynamicResource LabelTitle}" FontWeight="Bold" />
<ContentControl Grid.Row="0" Grid.Column="2"
DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}"
Content="{Binding Path=HeaderContent, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}" />
</Grid>
<ContentControl Grid.Row="1" Grid.Column="0"
DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}"
Content="{Binding Path=WindowContent, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}" />
<ContentControl Grid.Row="2" Grid.Column="0"
DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}"
Content="{Binding Path=ButtonPanel, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}" />
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>

Make attached properties work inside DataTemplate

I got an ItemsControl which uses a Canvas as ItemsPanel and its items are rendered to different WPF shapes depending on the bound type, basically like this:
<ItemsControl ItemsSource="{Binding PreviewShapes}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type local:UiPreviewLineViewModel}">
<Line X1="{Binding Start.X}" Y1="{Binding Start.Y}"
X2="{Binding End.X}" Y2="{Binding End.Y}"
StrokeThickness="0.75" Stroke="{Binding Brush}" x:Name="Line" ToolTip="{Binding Text}">
</Line>
</DataTemplate>
<DataTemplate DataType="{x:Type local:UiPreviewEllipsisViewModel}">
<Ellipse Canvas.Left="{Binding UpperLeft.X" Canvas.Top="{Binding UpperLeft.Y}"
Width="{Binding Width}" Height="{Binding Height}"
StrokeThickness="0.75" Stroke="{Binding Brush}" x:Name="Ellipse" ToolTip="{Binding Text}">
</Ellipse>
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas IsItemsHost="True" HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="SketchCanvas" ClipToBounds="False">
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
So I basically add objects to PreviewShapes of the viewmodel and depending on the type they are rendered to WPF Lines or Ellipses. That basically works but the attached properties Canvas.Left and Canvas.Top are ignored, even when using static values.
Also VS or ReSharper notifies me that the attached property has no effect in the current context.
How can I position the Ellipse on the canvas without using the attached properties? Or what other solution would be appropiate?
Unfortunately nobody felt like posting an answer.
First, Clemens links are helpful. The items will be inside a ContentPresenter which is the reason why setting Canvas.Left/Top on the Ellipsis does not work.
Solution 1
By adding a style to the item container the bindings for the position can be set there:
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding UpperLeft.X}" />
<Setter Property="Canvas.Top" Value="{Binding UpperLeft.Y}" />
</Style>
</ItemsControl.ItemContainerStyle>
This works but the DataTemplate placing <Line> will produce binding warnings because that view model does not have a property UpperLeft. Nevertheless it works for the ellipsis and the lines are placed by their X1, Y1, X2 and Y2 values.
Solution 2
If you would like to use a more fine grained control approach you can set the attached Canvas properties to the ContentPresenter by proxing them with a custom behaviour / attached property. Let's name it CanvasPointProxyBehavior, you could use it for the Ellipse like this:
<DataTemplate DataType="{x:Type local:UiPreviewEllipsisViewModel}">
<Ellipse behaviors:CanvasPointProxyBehavior.Point="{Binding UpperLeft}"
Width="{Binding Width}" Height="{Binding Height}"
StrokeThickness="0.75" Stroke="{Binding Brush}" x:Name="Ellipse" ToolTip="{Binding Text}">
</Ellipse>
</DataTemplate>
The Line will not need it. The code for this attached property might look like this:
public class CanvasPointProxyBehavior
{
public static readonly DependencyProperty PointProperty = DependencyProperty.RegisterAttached("Point", typeof(Point), typeof(CanvasPointProxyBehavior), new UIPropertyMetadata(null, PointChangedCallback));
public static void SetPoint(DependencyObject depObj, Point point)
{
depObj.SetValue(PointProperty, point);
}
public static Point GetPoint(DependencyObject depObj)
{
return depObj.GetValue(PointProperty) as Point;
}
private static void PointChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
UIElement uiElement = (dependencyObject as UIElement);
if (uiElement == null) return;
UIElement elementToBePositioned = uiElement;
var visualParent = VisualTreeHelper.GetParent(uiElement);
if (visualParent is ContentPresenter)
{
elementToBePositioned = visualParent as ContentPresenter;
}
var point = e.NewValue as Point;
if (point != null)
{
Canvas.SetLeft(elementToBePositioned, point.X);
Canvas.SetTop(elementToBePositioned, point.Y);
}
}
}
Hoping someone will find one or both solution useful.
Please note that I encountered the same ReSharper warning message as #ZoolWay, but in my case it was within a data grid, where I wanted the button on the right to be right-aligned instead of left-aligned:
Attached property setting "Grid.Column" has no effect in current
context and can be removed.
Here is the code where I had the warning, on the Button Grid.Column="2":
<Border VerticalAlignment="Center" Style="{DynamicResource InspectionsCustomDataGridHeader}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="10*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<Label Name="InspectionsDataGridTitle" Background="White" Content="{Binding InspectionsCollectionView.View.Count, ConverterParameter={x:Static resx:Resources.InspectionsDataGridTitle}, Converter={StaticResource DataGridHeaderCountConverter}}" Style="{DynamicResource InspectionsCustomDataGridHeaderLabel}" MouseDown="InspectionsDataGridTitle_MouseDown" />
<!-- more labels, etc... -->
<Button Grid.Column="2" Width="30" Height="30" Margin="0,0,10,0" Background="Transparent" BorderThickness="0" HorizontalAlignment="Right" Command="{Binding CreatePDFCommand,Mode=OneWay}" >
<StackPanel Orientation="Horizontal" Background="Transparent">
<Image Width="30" Height="30" Source="/Inspections;component/Icons/pdf_btn.png" />
</StackPanel>
</Button>
</StackPanel>
</Grid>
</Border>
This is how I fixed the warning, where I moved the button below the first StackPanel:
<Border VerticalAlignment="Center" Style="{DynamicResource InspectionsCustomDataGridHeader}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<Label Name="InspectionsDataGridTitle" Background="White" Content="{Binding InspectionsCollectionView.View.Count, ConverterParameter={x:Static resx:Resources.InspectionsDataGridTitle}, Converter={StaticResource DataGridHeaderCountConverter}}" Style="{DynamicResource InspectionsCustomDataGridHeaderLabel}" MouseDown="InspectionsDataGridTitle_MouseDown" />
<!-- more labels, etc... -->
</StackPanel>
<Button Grid.Column="2" Width="30" Height="30" Margin="0,0,10,0" Background="Transparent" BorderThickness="0" HorizontalAlignment="Right" Command="{Binding CreatePDFCommand,Mode=OneWay}" >
<StackPanel Orientation="Horizontal" Background="Transparent">
<Image Width="30" Height="30" Source="/Inspections;component/Icons/pdf_btn.png" />
</StackPanel>
</Button>
</Grid>
</Border>
HTH

How to set selected area in Listbox

I need to do something like that:
It's Listbox with custom DataTemplate for elements. (I drew green a whole one element of list.)
Now I have this:
If it's real - how to change my DataTemplate(or Listbox styles) to get first resul? (Somehow to set selected area)
DataTemplate
<DataTemplate x:Key="TrackDataTemplate">
<Grid Margin="0,-5,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding FirstPlatformName}" Grid.Row="0" Grid.Column="0"/>
<Path x:Name="Node"
Margin="10,0" Grid.Row="0" Grid.Column="1"
Data="M3.1999443,36.501999 L47.300057,36.501999 47.292366,36.517475 C43.192585,44.521747 34.86105,50 25.25,50 15.638952,50 7.3074172,44.521747 3.2076359,36.517475 z M25.25,0.5 C38.919049,0.49999976 50,11.580952 50,25.25 50,27.599367 49.672657,29.87228 49.061096,32.025615 L48.919384,32.501999 1.5806161,32.501999 1.438906,32.025615 C0.82734287,29.87228 0.5000003,27.599367 0.5,25.25 0.5000003,11.580952 11.580953,0.49999976 25.25,0.5 z"
Fill="{DynamicResource white75}" Stretch="Fill"
Width="17" Height="17"/>
<Rectangle x:Name="Connection" Grid.Row="1" Grid.Column="1"
HorizontalAlignment="Center" VerticalAlignment="Top"
Fill="{DynamicResource white75}" Height="17" Width="4" Margin="10,2,10,0"/>
<TextBlock Grid.Row="1" Grid.Column="2" TextWrapping="Wrap"
Text="{Binding TsAndChannelNumber}"/>
</Grid>
</DataTemplate>
Listbox
<ListBox Grid.Column="1"
SelectedItem="{Binding SelectedTrackSegment}"
ItemsSource="{Binding SelectedTrack.Segments}"
ItemTemplate="{StaticResource TrackDataTemplate}"
Margin="30,20,30,0"/>
For complete control over the ListBoxItem you probably need to change the Template in ItemContainerStyle.
Heres a little test project to show what I mean.
NB Ive added 2 grids around your textblocks so that the Background Property can be changed using the Triggers.
Xaml
<ListBox x:Name="MyList">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid Margin="0,-5,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid x:Name="PlatformGrid">
<TextBlock Text="{Binding FirstPlatformName}" />
</Grid>
<Path x:Name="Node"
Margin="10,0" Grid.Row="0" Grid.Column="1"
Data="M3.1999443,36.501999 L47.300057,36.501999 47.292366,36.517475 C43.192585,44.521747 34.86105,50 25.25,50 15.638952,50 7.3074172,44.521747 3.2076359,36.517475 z M25.25,0.5 C38.919049,0.49999976 50,11.580952 50,25.25 50,27.599367 49.672657,29.87228 49.061096,32.025615 L48.919384,32.501999 1.5806161,32.501999 1.438906,32.025615 C0.82734287,29.87228 0.5000003,27.599367 0.5,25.25 0.5000003,11.580952 11.580953,0.49999976 25.25,0.5 z"
Fill="Blue" Stretch="Fill"
Width="17" Height="17"/>
<Rectangle x:Name="Connection" Grid.Row="1" Grid.Column="1"
HorizontalAlignment="Center" VerticalAlignment="Top"
Fill="Blue" Height="17" Width="4" Margin="10,2,10,0"/>
<Grid x:Name="TSGrid" Grid.Row="1" Grid.Column="2">
<TextBlock TextWrapping="Wrap" Text="{Binding TsAndChannelNumber}"/>
</Grid>
</Grid>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Selector.IsSelectionActive" Value="True"/>
<Condition Property="IsSelected" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="PlatformGrid" Value="Red"/>
<Setter Property="Background" TargetName="TSGrid" Value="Red"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
MainWindows.cs
public MainWindow()
{
InitializeComponent();
Loaded += (s, args) =>
{
this.DataContext = this;
MyList.ItemsSource = LoadSegments();
};
}
private static List<Segment> LoadSegments()
{
var segments = new List<Segment>
{
new Segment { FirstPlatformName = "FPName01", TsAndChannelNumber = "TSNumber0(ChannelNumber0" },
new Segment { FirstPlatformName = "FPName01", TsAndChannelNumber = "TSNumber0(ChannelNumber1" },
new Segment { FirstPlatformName = "FPName01", TsAndChannelNumber = "TSNumber0(ChannelNumber2" },
new Segment { FirstPlatformName = "FPName01", TsAndChannelNumber = "TSNumber0(ChannelNumber3" },
new Segment { FirstPlatformName = "FPName01", TsAndChannelNumber = "TSNumber0(ChannelNumber4" }
};
return segments;
}
Segment.cs
public class Segment
{
public string FirstPlatformName { get; set; }
public string TsAndChannelNumber { get; set; }
}
You will ideally need to 'Edit a copy' of the ItemContainerStyle template in Blend so you get access to all the standard behaviours and then edit the Trigger IsSelected as above
Hope that helps
But I suggest to use two ListBox and use IsSynchronizedWithCurrentItem property to true. So when you make selection on one, it will select the same item on other automatically. And you can define your own data template for each listbox.

click of a button defined inside DataTemplate

i have a template defiend as below:
<Window.Resources>
<DataTemplate x:Key="TemplateDetailView">
<Expander x:Name="exp" IsExpanded="True" FontSize="13" FontWeight="SemiBold">
<Expander.Header>
<TextBlock Foreground="{DynamicResource BlackColorBrush}">
<TextBlock.Text>
<MultiBinding StringFormat="{} {0} {1}">
<Binding Path="persons.Count"/>
<Binding Path="DisplayText"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Expander.Header>
<ListBox x:Name="lst" ItemsSource="{Binding persons}" Grid.Row="1" BorderThickness="0" Foreground="{DynamicResource BlackColorBrush}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="stretch"/>
<Setter Property="Background" Value="Transparent" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border DataContext="{Binding}" BorderThickness="2" Margin="0,0,0,-1" BorderBrush="{DynamicResource NormalBorderBrush}" Visibility="{Binding IsVisibility}">
<DockPanel Margin="15,5" Background="Transparent">
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" Background="Transparent">
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
<CheckBox VerticalAlignment="Center" VerticalContentAlignment="Center" Tag="{Binding}" Padding="4,0" Style="{DynamicResource CheckBoxStyleDetailedViewStyle}" Checked="CheckBox_Checked" IsChecked="{Binding Acknowledged}" Height="30" Margin="3,5,3,3" Width="Auto"/>
</StackPanel> <ScrollViewer CanContentScroll="True" MinHeight="25" DockPanel.Dock="Left" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
<ItemsControl ScrollViewer.CanContentScroll="True" DataContext="{Binding}" ItemsSource="{Binding AlertActionsDefinition.Children}" x:Name="lstButton" ButtonBase.Click="lstButton_Click">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Background="Transparent" >
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate >
<DataTemplate>
<Button Click="lstButton_Click" Content="{Binding Text}" Tag="{Binding}" Padding="4,0" IsEnabled="{Binding Visible}" Visibility="{Binding Visibility}" Height="30" Margin="3,5,3,3"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer> </StackPanel>
<Grid Width="700">
<Grid.RowDefinitions>
<RowDefinition Height="3"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="3"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="3"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="3"/>
<RowDefinition Height="*"/>
<RowDefinition Height="3"/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding Text}" Grid.Row="1" FontWeight="Bold" FontSize="14"/>
<TextBlock Text="{Binding Description}" Grid.Row="3" FontSize="13"/>
</Grid>
</DockPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Expander>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=lst,Path=Items.Count}" Value="0">
<Setter Property="Visibility" Value="Collapsed" TargetName="exp"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox x:Name="listBox" ItemTemplate="{DynamicResource TemplateShortView}" ItemsSource="{Binding}" BorderThickness="0">
</ListBox>
</Grid>
listbox is binded to class persons. initially the list box is loaded with short view which is then loaded to have detailed view template defined above. the problem i am facing is the click event on button inside template. click wont be fired at all some times and some times takes two to three clicks to raise the event.
could any one help me out to trace it down ?
I reduced your code to suit my testing and it works perfectly for me! I receive all the events correctly. In fact I receive lstButton_Click twice for each button clicked... (due to bubbling at Button and ItemsControl level).
Code Behind...
/// <summary>
/// Interaction logic for Window6.xaml
/// </summary>
public partial class Window6 : Window
{
public Window[] JustList
{
get
{
return new Window[] { this };
}
}
public List<Person> persons
{
get
{
return new List<Person>()
{
new Person()
{
Acknowledged = true,
Description = "Person 1",
Text = "Person1",
DisplayText = "I am Person 1"
},
new Person()
{
Acknowledged = true,
Description = "Person 2",
Text = "Person2",
DisplayText = "I am Person 2"
}
};
}
}
public Window6()
{
InitializeComponent();
}
void lstButton_Click(object sender, RoutedEventArgs e)
{
var i = 0 ;
}
void CheckBox_Checked(object sender, RoutedEventArgs e)
{
var i = 0;
}
}
public class Person
{
public string DisplayText { get; set; }
public string Text { get; set; }
public bool Acknowledged { get; set; }
public string Description { get; set; }
public Visibility IsVisibility { get; set; }
public List<Person> Children
{
get
{
return new List<Person>()
{
new Person()
{
Acknowledged = true,
Description = "Child 1",
Text = "Child1",
DisplayText = "My Child 1"
},
new Person()
{
Acknowledged = true,
Description = "Child 2",
Text = "Child2",
DisplayText = "My Child 2"
}
};
}
}
}
XAML ...
<Window.Resources>
<DataTemplate x:Key="TemplateDetailView">
<Expander x:Name="exp" IsExpanded="True"
FontSize="13" FontWeight="SemiBold">
<Expander.Header>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{} {0} {1}">
<Binding Path="persons.Count"/>
<Binding Path="DisplayText"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Expander.Header>
<ListBox x:Name="lst" ItemsSource="{Binding persons}"
Grid.Row="1" BorderThickness="0">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment"
Value="stretch"/>
<Setter Property="Background" Value="Transparent" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border DataContext="{Binding}"
BorderThickness="2"
Margin="0,0,0,-1" BorderBrush="Red">
<DockPanel Margin="15,5"
Background="Transparent">
<StackPanel DockPanel.Dock="Bottom"
Orientation="Horizontal"
Background="Transparent">
<StackPanel HorizontalAlignment="Left"
Orientation="Horizontal">
<CheckBox VerticalAlignment="Center"
VerticalContentAlignment="Center"
Tag="{Binding}"
Padding="4,0"
Checked="CheckBox_Checked"
IsChecked="{Binding Acknowledged}"
Height="30"
Margin="3,5,3,3" Width="Auto"/>
</StackPanel>
<ScrollViewer CanContentScroll="True"
MinHeight="25"
DockPanel.Dock="Left"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Disabled">
<ItemsControl
ScrollViewer.CanContentScroll="True"
DataContext="{Binding}"
ItemsSource="{Binding Children}"
x:Name="lstButton"
ButtonBase.Click="lstButton_Click">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel
Orientation="Horizontal"
Background="Transparent" >
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate >
<DataTemplate>
<Button Click="lstButton_Click"
Content="{Binding Text}"
Tag="{Binding}"
Padding="4,0"
IsEnabled="{Binding
Visible}"
Visibility="{Binding
Visibility}"
Height="30"
Margin="3,5,3,3"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</StackPanel>
<Grid Width="700">
<Grid.RowDefinitions>
<RowDefinition Height="3"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="3"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="3"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="3"/>
<RowDefinition Height="*"/>
<RowDefinition Height="3"/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding Text}" Grid.Row="1"
FontWeight="Bold" FontSize="14"/>
<TextBlock Text="{Binding Description}"
Grid.Row="3" FontSize="13"/>
</Grid>
</DockPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Expander>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=lst,Path=Items.Count}"
Value="0">
<Setter Property="Visibility" Value="Collapsed" TargetName="exp"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox x:Name="listBox" ItemTemplate="{StaticResource TemplateDetailView}"
ItemsSource="{Binding RelativeSource={RelativeSource
AncestorType={x:Type Window}},
Path=JustList}"
BorderThickness="0">
</ListBox>
</Grid>

WPF items not visible when grouping is applied

I'm having this strange issue with my ItemsControl grouping. I have the following setup:
<ItemsControl Margin="3" ItemsSource="{Binding Communications.View}" >
<ItemsControl.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander>
<Expander.Header>
<Grid>
<Grid.ColumnDefinitions >
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding ItemCount, StringFormat='{}[{0}] '}" FontWeight="Bold" />
<TextBlock Grid.Column="1" Text="{Binding Name, Converter={StaticResource GroupingFormatter}, StringFormat='{}Subject: {0}'}" FontWeight="Bold" />
</Grid>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ItemsControl.GroupStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock FontWeight="Bold" Text="{Binding Inspector, Converter={StaticResource NameFormatter}, StringFormat='{}From {0}:'}" Margin="3" />
<TextBlock Text="{Binding SentDate, StringFormat='{}{0:dd/MM/yy}'}" Grid.Row="1" Margin="3"/>
<TextBlock Text="{Binding Message }" Grid.Column="1" Grid.RowSpan="2" Margin="3"/>
<Button Command="vm:CommunicationViewModel.DeleteMessageCommand" CommandParameter="{Binding}" HorizontalAlignment="Right" Grid.Column="2">Delete</Button>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
In my ViewModel, I expose a CollectionViewSource named 'Communications'. I proceed to adding a grouping patter like so:
Communications.GroupDescriptions.Add(new PropertyGroupDescription("Subject"));
Now, the problem i'm experience is the grouping work fine, but I can't see any items inside the groups. What am I doing wrong? Any pointers would be much appreciated.
I can't seem to reproduce the problem - I assume you are using a CollectionViewSource? It might be because you bound to the View property directly.
Here's the C# code I used:
public class Communication
{
public string Subject { get; set; }
public string Body { get; set; }
}
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
var source = (CollectionViewSource)Resources["Communications"];
source.Source = new List<Communication>()
{
new Communication { Subject = "WPF 4.0", Body = "I love what's happening with 4.0"},
new Communication { Subject = "WPF 4.0", Body = "I hear the text rendering is the best feature"},
new Communication { Subject = "Blend 3.0", Body = "Behaviors in Blend 3 change everything"}
};
source.GroupDescriptions.Add(new PropertyGroupDescription("Subject"));
}
}
Here is the XAML - it's the same as yours but with a couple of things removed since I don't have your converters or commands:
<Window
x:Class="GroupStyleDemo.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300"
>
<Window.Resources>
<CollectionViewSource x:Key="Communications" />
</Window.Resources>
<Grid>
<ItemsControl Margin="3" ItemsSource="{Binding Source={StaticResource Communications}}" >
<ItemsControl.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander>
<Expander.Header>
<Grid>
<Grid.ColumnDefinitions >
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding ItemCount, StringFormat='{}[{0}] '}" FontWeight="Bold" />
<TextBlock Grid.Column="1" Text="{Binding Path=Name}" FontWeight="Bold" />
</Grid>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ItemsControl.GroupStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Body }" Grid.Column="1" Grid.RowSpan="2" Margin="3"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
After hitting this problem myself I discovered the cause: the template for ItemsControl directly including a panel with IsItemsHost="true".
You must insert an ItemPresenter into your template and set the ItemsControl.ItemsPanel property instead.

Resources