Binding ZIndex from DataTemplate - c#

I have a View that is basically setup like this:
<Grid>
<ViewBox>
<Grid>
<ItemsControl ItemsSource="{Binding MyItems}"
ItemTemplate="{Binding Source={StaticResource MyItemsDataTemplate}}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</ViewBox>
</Grid>
The DataTemplate used here can be reduced to this:
<DataTemplate x:Key="AreaItemDisplayDataTemplate">
<Canvas Grid.ZIndex={Binding Z}>
<Grid>
// an shape is displayed here...
</Grid>
</Canvas>
I would now expect the ZIndex to be bound to the Z property of the individual items. When i debug the code, i can also see, that the Z property getter is accessed when i would expect it (whenever i raise the propertychanged event for it, eg) so i assume the binding to work correctly.
However, the ZIndex is not working as expected. The binding to the value has no effect on the actual displayed Z Order. Where am i going wrong with this code?

The content of the DataTemplate gets wrapped in a ContentPresenter so the Canvas in the DataTemplate isn't a direct child of the ItemsPanel Grid. That is the reason the ZIndex property doesn't do anything.
Move the ZIndex Binding to the ItemContainerStyle and it should work.
<ItemsControl ItemsSource="{Binding MyItems}"
ItemTemplate="{Binding Source={StaticResource MyItemsDataTemplate}}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Grid.ZIndex" Value="{Binding Z}"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>

Related

UniformGrid Grid.Row Grid.Column not being adhered to

Following on from this question (DataTemplateSelector for Uniform Grid binding?), I still am not getting my Buttons/Textblocks to adhere to the row and the column that they are bound to in the view model. I will only post the XAML as I know the row and column bindings are correct (Live Visual Tree tells me Row is 1 and Column is 1 for example, but on the grid it shows otherwise...).
If you need anymore code let me know. This is the small bit of XAML.
<Grid DockPanel.Dock="Left" Background="Transparent" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinWidth="800" Height="400">
<ItemsControl ItemsSource="{Binding ObjCompositeCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid DockPanel.Dock="Top" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Name="objGrid" Grid.Row="1"
Rows="{Binding RowCount}"
Columns="{Binding ColumnCount}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Row" Value="{Binding Row}"/>
<Setter Property="Grid.Column" Value="{Binding Column}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type engine:ObjA}">
<Button Content="{Binding Id}" />
</DataTemplate>
<DataTemplate DataType="{x:Type engine:GridLabeller}">
<TextBlock Text="{Binding HeaderName}"/>
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
</Grid>
A UniformGrid in WPF doesn't care about the Grid.Row and Grid.Column attached properties. You need to create a Grid with RowDefinitions and ColumnsDefinitions for setting these properties to have any effect.
You may create a Grid programmatically in the view based on the values of the RowCount and ColumnCount source properties.

WrapPanel not wrapping when using it with ItemControl

I have a WrapPanel that I'm filling in my ViewModel with UserControls:
<WrapPanel Width="250" Orientation="Horizontal" Margin="3">
<ItemsControl ItemsSource="{Binding PlaceableObjectsContent}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:PlaceableObjectViewModel}">
<local:PlaceableObjectUserControl>
<local:PlaceableObjectUserControl.InputBindings>
<MouseBinding MouseAction="LeftClick"
Command="{Binding DataContext.OnPlaceableObjectClicked, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}"/>
</local:PlaceableObjectUserControl.InputBindings>
</local:PlaceableObjectUserControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</WrapPanel>
When I fill them manuell with random Controls, everything works fine! I already read something about problems because of Using ItemTemplate!?
If its true, how can I manage that?
Thanks
You're putting a single ItemsControl inside a WrapPanel. That won't do anything. If you want your ItemsControl to use a WrapPanel to host its own items, here's how:
<ItemsControl
ItemsSource="{Binding PlaceableObjectsContent}"
Width="250"
Margin="3"
>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- etc. -->
Note that something has to constrain the width of the ItemsControl for this to work: Either it must be limited by the size of its parent, or a Grid Column, or even by setting the Width or MaxWidth properties of the ItemsControl element itself, either directly or via a Style.

Databind DockPanel

I'm trying to databind a Dockpanel in wpf to a viewmodel collection. I'm using this in order to create a customizable form and so I will not know how many children should be in the dockpanel until runtime.
The problem that I am having is that the attached property DockStyle.Dock doesn't seem to be getting applied when I set it from within a data template. The following xaml is a simplified version of what I am doing. I would expect the first button to fill up the top portion of the screen but what really happens is that they are stacked horizontally. Even hardcoding the DockPanel.Dock property has no effect on the layout of the buttons. When I look at the Visual Tree in XAMLPad I notice that there are ContentPresenters as children of the DockPanel instead of the buttons. Do ContentPresenters get layed out differently then other elements? Is there another technique to databinding to DockPanels?
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Grid>
<ItemsControl >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<DockPanel LastChildFill="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button DockPanel.Dock="{Binding}" Content="{Binding}"></Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
<sys:String>Top</sys:String>
<sys:String>Bottom</sys:String>
<sys:String>Left</sys:String>
<sys:String>Right</sys:String>
<sys:String>Top</sys:String>
<sys:String>Top</sys:String>
<sys:String>Top</sys:String>
</ItemsControl>
</Grid></Page>
The reason that the items aren't docked is because the control in the DataTemplate is not a direct child of the DockPanel. I believe that the ItemsControl creates one ContentPresenter for each item, just like how a ListBox creates one ListBoxItem for each item.
You could try using the ItemContainerStyle to dock the controls. I think that any properties set on it should be set on the ContentPresenter. Something like this might work:
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<DockPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="DockPanel.Dock" Value="{Binding}" />
</Style>
</ItemsControl.ItemContainerStyle>
...
</ItemsControl>
I'm not sure if binding a string to the Dock property will work or not, though. You might try using the values in the enum directly to see if that helps as well.
This is because your Button is wrapped by ItemsControl in ContentPresenter which does not have DockPanel.Dock set. Try setting ItemContainerStyle to something like this:
<ItemsControl.ItemContainerStyle>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="DockPanel.Dock" Value="{Binding}"/>
</Style>
</ItemsControl.ItemContainerStyle>

Changing ListBox ItemsPanelTemplate has gotten me into trouble?

I have a CustomControl (say CC) that has been inherited from ContentControl and contains a ScrollViewer which includes a ContentPresenter. When I put a ListBox into the CC it works without any problem. But when I set the ItemsPanelTemplate of the ListBox it doesn't notify CC to scroll into the ListBox selected item.
What's the reason for it? -Thanks
UPDATE:
I'll encounter the problem described above only if I set HorizontalScrollBarVisibility or VerticalScrollBarVisibility to Hidden and customize the ItemsPanelTemplate of the ListBox simultaneously. (I need to hide scollbars.)
I wonder if hiding Scrollbars prevents ScrollViewer contents from notifying it to bring selected item into view, why this issue doesn't happen when I don't change items panel???
Generic.xaml:
<ResourceDictionary ...>
<Style TargetType="{x:Type local:CustomControl1}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<Border ...>
<ScrollViewer ...
CanContentScroll="True"
HorizontalScrollBarVisibility="Hidden" « PROBLEM
VerticalScrollBarVisibility="Hidden"> «
<ContentPresenter Content="{TemplateBinding Content}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
MainWindow.xaml:
<Window x:Class="MyNamespace1.MainWindow"
...
xmlns:proj="clr-namespace:MyNamespace0;assembly=...">
<Grid>
<proj:CustomControl1 x:Name="CC">
<ListBox>
<ListBox.ItemsPanel> «
<ItemsPanelTemplate> «
<StackPanel Orientation="Horizontal"/> « PROBLEM
</ItemsPanelTemplate> «
</ListBox.ItemsPanel> «
<!--content goes here-->
</ListBox>
</proj:CustomControl1>
</Grid>
</Window>
Have you set the IsItemsHost property for the Panel in the ItemsPanelTemplate to True?
E.g. if the itemspaneltemplate should use a Canvas:
<ItemsPanelTemplate>
<Canvas IsItemsHost="True" />
</ItemsPanelTemplate>
Related
StackPanel treats its content has having infinite space..
You will have to limit its size explicitly, or change it to other panel, Grid for example.
Try this:
<ItemsPanelTemplate>
<Grid/>
</ItemsPanelTemplate>
Or:
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Width="100" Height="100"/>
</ItemsPanelTemplate>

WPF: ItemsControl and DataContext

I have a main window with a single user control in it, called SuperMode. SuperMode consists of a collection of people and each person in this collection has their own collection of tasks. Sounds simple, right?
From file SuperMode.xaml:
<UserControl
x:Class="Prototype.SuperMode"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Prototype"
DataContext="{Binding RelativeSource={RelativeSource Self}}"> <!-- NOTE! -->
<!-- Look at how I'm setting the DataContext, as I think it's
important to solve the problem! -->
<ScrollViewer CanContentScroll="True">
<ItemsControl ItemsSource="{Binding People}" Margin="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
</UserControl>
This works fine and I can see four people as I expect! Now all I have to do is get the XAML right for the Person user control so that all of their tasks are displayed as well.
As you can see, I'm using the People property to populate the control with items. The People property has type ObservableCollection<Person>, where Person is another user control as such...
From Person.xaml:
<UserControl
x:Class="Prototype.Person"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Prototype">
<Border Background="Black" CornerRadius="4" Margin="1">
<ItemsControl ItemsSource="{Binding Tasks}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Border>
</UserControl>
Tasks here is a property of Person with type ObservableCollection<Task>. This is where it gets stuck! Apparently WPF cannot find any Tasks property and looking at the output window from VS2008, I find the following:
System.Windows.Data Error: 39 : BindingExpression path error: 'Tasks' property not found on 'object' ''SuperMode' (Name='SuperMode')'. BindingExpression:Path=Tasks; DataItem='SuperMode' (Name='SuperMode'); target element is 'ItemsControl' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')
Now I'm lost. It seems that I have to set the DataContext attribute on each Person, otherwise it will still think that the data context is SuperMode, but how do I do that?
Ignoring the rather unpleasant design you have (you should look into MVVM), you should be able to set the DataContext for the child UserControls as follows:
<ItemsControl ItemsSource="{Binding People}" Margin="1">
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="FrameworkElement.DataContext" Value="{Binding RelativeSource={RelativeSource Self}}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>

Categories

Resources