Shapes don't appear to be reacting to setting ZIndex? - c#

Currently, I have three different types of objects that I draw to the screen (I'm using a ZoomableCanvas, if that makes a difference): beacons (concentric blue circles), tables (black rectangles), and debugRectangles (gold rectangles. The objects are displayed/layered on the Z-axis according to the order in which they're added to the ItemSource, but it's not always possible for me to add shapes in Z-ordering.
This image shows how it looks, depending on the order of objects being added. I'd like for the shapes to respect the Panel.ZIndexes I've set, and in doing so, look like the top image (except with the gold rectangle in the back).
<Style.Triggers>
<!-- Gold rectangles drawn here (color set in code) -->
<DataTrigger Binding="{Binding type}" Value="rectangle">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Rectangle Fill="{Binding fill}" Stroke="{Binding border}" StrokeThickness="5"
Width="{Binding width}" Height="{Binding height}" Panel.ZIndex="-1"/>
<TextBlock Text="{Binding i}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<!-- Black rectangles drawn here -->
<DataTrigger Binding="{Binding type}" Value="tableBlock">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Rectangle Fill="{Binding fill}" Stroke="Black" StrokeThickness="5"
Width="{Binding width}" Height="{Binding height}" Panel.ZIndex="50"/>
<TextBlock Text="{Binding i}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<!-- Blue circles drawn here -->
<DataTrigger Binding="{Binding type}" Value="beacon">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Ellipse Fill="DodgerBlue" Width="{Binding outerRadius}" Height="{Binding outerRadius}" Panel.ZIndex="97"/>
<Ellipse Fill="SkyBlue" Width="{Binding innerRadius}" Height="{Binding innerRadius}" Panel.ZIndex="98"/>
<TextBlock Text="{Binding id}" HorizontalAlignment="Center" VerticalAlignment="Center" Panel.ZIndex="99"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
Within a template, they follow the order (I can rearrange the components of a beacon), but relative to each other, no dice. Can anyone identify the issue?

ZoomableCanvas relies upon Panel to render, which means it uses the standard ordering for ZIndex.
<Window x:Class="ZoomableApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<ZoomableCanvas>
<Rectangle Fill="Green" Height="250" Width="250" />
<Rectangle Fill="Red" Height="200" Width="400" Panel.ZIndex="2" />
<Rectangle Fill="Blue" Height="400" Width="200" />
</ZoomableCanvas>
</DockPanel>
</Window>
The problem you are having is that your visual tree looks like this:
ZoomableCanvas
Grid
Ellipse with Panel.ZIndex="98"
Since Ellipse is a child of Grid, the ZOrder doesn't affect the ZoomableCanvas, but instead sets the ZIndex of the Ellipse relative to the other children of the grid. In order to change the layering of the ZoomableCanvas, you need to set the ZOrder property on the child of the ZoomableCanvas – the Grid:
ZoomableCanvas
Grid with Panel.ZIndex="98"
Ellipse
Example:
<DataTemplate>
<Grid Panel.ZIndex="100">
<Rectangle Fill="{Binding fill}" Stroke="Black" StrokeThickness="5"
Width="{Binding width}" Height="{Binding height}" Panel.ZIndex="50"/>
<TextBlock Text="{Binding i}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
If you are using a ListBox, you end up with additional levels in your tree:
ZoomableCanvas
ListBoxItem with ItemContainerStyle setting Panel.ZIndex="98"
Grid
Ellipse
Example of use:
<ListBox>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Panel.ZIndex" Value="98" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
If you have multiple varying ZIndexes, you could expose a property on the data item and bind to that, or use a ItemContainerStyleSelector to do the logic in code-behind.
You can also use Snoop to look at the created tree to identify these sorts of issues.

Have you tried setting the Panel.ZIndex on the Grids?

Related

WPF - How to give priority to the second element of DockPanel

If have a DockPanel with two Border elements, first with HorizontalAlignment="Left" and second with HorizontalAlignment="Right". The width of entire DockPanel is fixed but widthes of Borders should be changed depending to its content. Both borders have TextBlockss. First TextBlock has word wrapping turned on the second is just one word. I want at first the second Border to be drawan and it should take all needed space and remaining space will be occupied by the first Border and it should use word wrapping to draw the content. This is my code which does not work because it first draws the first Border so no padding is left for the second one. Can you hint how to give priority to the second(right) element of DockPanel?
<DockPanel>
<Border Background="#FFFFFF" HorizontalAlignment="Left" CornerRadius="4 0 0 4" Height="48" MaxWidth="183">
<ContentControl VerticalAlignment="Center">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding Mode}" Value="trial">
<Setter Property="Content">
<Setter.Value>
<WrapPanel Orientation="Horizontal" MaxWidth="190" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock FontSize="12" TextWrapping="Wrap" Padding="11, 0, 11, 0">
<Run Text="{Binding TrialText1, Mode=OneWay}"/>
</TextBlock>
</WrapPanel>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</Border>
<Border CornerRadius="0 4 4 0" HorizontalAlignment="Right" MaxWidth="104" MinWidth="83">
<Border.Background>
<SolidColorBrush Color="#FFFFFF" Opacity="0.4"/>
</Border.Background>
<ContentControl VerticalAlignment="Center">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding Mode}" Value="trial">
<Setter Property="Content">
<Setter.Value>
<WrapPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="{Binding PlanTitleText1}" FontSize="12" HorizontalAlignment="Center"
</WrapPanel>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</Border>
</DockPanel>
You can use Grid instead. Define 2 Columns. Make the second one auto adjust how much space it needs and allow the first one to take all the remaining space.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" (...)>
(...)
</Border>
<Border Grid.Column="1" (...)>
(...)
</Border>
</Grid>

Using WindowChrome Class to set title bar background

I am wanting to just set the title bar and border of a WPF window but the title background property doesn't look to be exposed in the class.
I want to leave all default Window behavior and just set the color property of Title Bar and Border
What is the correct property to set?
I am refrencing: https://learn.microsoft.com/en-us/dotnet/api/system.windows.shell.windowchrome?view=netframework-4.7.2
<ResourceDictionary>
<Style x:Key="CustomWindowStyle" TargetType="{x:Type Window}">
<Setter Property="WindowChrome.WindowChrome">
<Setter.Value>
<WindowChrome/>
</Setter.Value>
</Setter>
<Setter Property="??" Value="Blue"/>
</Style>
</ResourceDictionary>
The only property I see is the Title Property and setting its color has no effect
So I resolved this and it was more involved then I had originally thought. Since the title bar is in the non-client area when editing it I would lose the visibility of the corner buttons.
In the end I had to reconstruct the title bar and create a class to implement the buttons to get the look I desired.
This will give you a window with a border and the title bar will also have a color. You need to implement the corner buttons though.
xmlns:shell="http://schemas.microsoft.com/netfx/2009/xaml/presentation"
<Style x:Key="StandardStyle" TargetType="{x:Type Window}">
<Setter Property="shell:WindowChrome.WindowChrome">
<Setter.Value>
<shell:WindowChrome
/>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}" >
<Grid>
<!--Title Panel-->
<DockPanel LastChildFill="True">
<Border Background="Blue" DockPanel.Dock="Top"
Height="{x:Static SystemParameters.CaptionHeight}" x:Name="titlebar">
<Grid>
<!--Title text only-->
<TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Title}"
VerticalAlignment="Top" HorizontalAlignment="Center" Background="Transparent" />
<usercontrols:CornerButtons HorizontalAlignment="Right"/>
</Grid>
</Border>
<!--Provides the actual content control-->
<Border Margin="0,0,0,0" >
<AdornerDecorator>
<ContentPresenter Content="{TemplateBinding Content}"/>
</AdornerDecorator>
</Border>
</DockPanel>
<!--Provides the actual window border-->
<Border
Margin="0,0,0,0"
Background="White"
Grid.ZIndex="-1"
BorderThickness="2,2,2,2" BorderBrush="Blue"
>
</Border>
<!--This is the top left system button-->
<!--<Button
Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(shell:WindowChrome.WindowChrome).ResizeBorderThickness}"
Padding="1"
HorizontalAlignment="Left"
VerticalAlignment="Top"
shell:WindowChrome.IsHitTestVisibleInChrome="True"
Command="{x:Static shell:SystemCommands.ShowSystemMenuCommand}"
CommandParameter="{Binding ElementName=CalcWindow}">
<Image
Width="16"
Height="16"
shell:WindowChrome.IsHitTestVisibleInChrome="True"
Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Icon}" />
</Button>-->
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

distance between items in listview datatemplate wpf

hi i created a datatemplate for listview now i have 2 problem first is when mouse focus on button my image hide you can see it on below image.
problem 1 and 2
two is The distance between the items is tall and I want their distance being just one line (see below image)
see this image
and this is my datatemplate:
<DataTemplate>
<Border Background="#f0f4f7">
<StackPanel Background="#f5f6fa" Margin="1,1,1,1" VerticalAlignment="Top">
<Border Background="#edf0f5" BorderThickness="5">
<Grid Background="#ffffff" Height="30">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel Background="#ffffff" Margin="5" Orientation="Horizontal">
<Button Height="20" Width="20" BorderBrush="Transparent" BorderThickness="0" Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.DeleteCommand}">
<Button.Background>
<ImageBrush ImageSource="..\Resources\Delete.png"/>
</Button.Background>
</Button>
<Button Height="20" Width="20" BorderBrush="Transparent" BorderThickness="0" Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.EditCommand}">
<Button.Background>
<ImageBrush ImageSource="..\Resources\Edit.png"/>
</Button.Background>
</Button>
</StackPanel>
<TextBlock Name="txtPhon" Foreground="#7c7f84" HorizontalAlignment="Right" Grid.Column="1" Text="{Binding Path=HomePhoneNumber}"
Margin="0,5,5,5"/>
</Grid>
</Border>
</StackPanel>
</Border>
</DataTemplate>
The problem with mouse making the picture disappear is because of the default template to a button. When you mouseover it gives that blue effect. I think it's in a border which is inside the template so it's above the background.
You can re-template the button to avoid that if you just want your image inside it.
Depending on your exact requirements then you might want slightly different but roughly:
<Button.Template>
<ControlTemplate>
<Border>
<ContentPresenter />
</Border>
</ControlTemplate>
</Button.Template>
You could make the whole template just an image.
Particularly if your icons are one colour, I would recommend using a path and define your icons as geometries in a resource dictionary.
Like the letter in this:
https://social.technet.microsoft.com/wiki/contents/articles/32610.wpf-layout-lab.aspx
The gap between your items.
There's padding in the default itemcontainer styling.
You can avoid that by, again, changing the template something like:
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
I notice you also have a margin set on your TextBlock, I would temporarily change that and see if that's also part of the problem.
<TextBlock Name="txtPhon" Foreground="#7c7f84" HorizontalAlignment="Right" Grid.Column="1" Text="{Binding Path=HomePhoneNumber}"
**Margin="0,0,5,0"/>**
In order to explore this sort of issue I find Snoop is invaluable. It's free.
Once installed run it after your app.
Drag one of the sight + things over your running window.
Mouse over a suspect piece of UI.
Press Ctrl+Shift and it'll show you all the controls in there and their properties. You can change values in the window and explore what effect the change would have immediately.

WPF ScrollViewer scroll-bars not changing size

I am not a WPF expert so please excuse my inappropriate use of terms. I have a ScrollViewer where I am displaying a captured image. And I have a slider with which I am zooming the image in and out. Zooming works fine, but the scrollbars are not changing their size. Hence when the image goes beyond the boundaries, I cannot scroll and view it. As if the scrollbars become useless because they haven't changed their size. Here is my XAML:
The Slider:
<Slider DockPanel.Dock="Right" Width="100" VerticalAlignment="Center" Minimum="0.2" Maximum="5"
Interval="1" Value="{Binding ScaleFactor}"/>
The rest of XAML:
<Border BorderThickness="1" BorderBrush="Black" Grid.Row="1">
<Grid>
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
CanContentScroll="True">
<ItemsControl ItemsSource="{Binding ItemCollection}" Margin="0"
Width="{Binding Root.Boundary.Width}" Height="{Binding Root.Boundary.Height}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas>
<Canvas.LayoutTransform>
<ScaleTransform ScaleX="{Binding ScaleFactor}"
ScaleY="{Binding ScaleFactor}"CenterX="0" CenterY="0"/>
</Canvas.LayoutTransform>
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Image x:Name="capturedImage"
Source="{Binding Image}"
Width="{Binding Boundary.Width}"
Height="{Binding Boundary.Height}"/>
<Path x:Name="captureContour"
Data="{Binding Outline}"
Stroke="Black" StrokeThickness="4" Opacity="0.5"
StrokeLineJoin="Round">
<Path.LayoutTransform>
<ScaleTransform ScaleX="{Binding OutlineScale.X}"
ScaleY="{Binding OutlineScale.Y}" CenterX="0"CenterY="0"/>
</Path.LayoutTransform>
</Path>
</Grid>
<DataTemplate.Triggers>
<Trigger SourceName="capturedImage" Property="IsMouseOver"
Value="True">
<Setter TargetName="captureContour" Property="Stroke"
Value="Blue"/>
<Setter TargetName="captureContour" Property="BitmapEffect">
<Setter.Value>
<DropShadowBitmapEffect/>
</Setter.Value>
</Setter>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Border>
The issue is due to the Canvas used as ItemsPanel. as Canvas does not expand or collapse with the size of it's children so ScrollViewer does not detect the change.
As a quick solution change the ItemsPanel to Grid. Since your example does not seems to be using Canvas properties i.e. Canvas.Left or Canvas.Top, this change may not make any difference in the appearance.
example
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid HorizontalAlignment="Left" VerticalAlignment="Top">
<Grid.LayoutTransform>
<ScaleTransform ScaleX="{Binding ScaleFactor}"
ScaleY="{Binding ScaleFactor}"
CenterX="0"
CenterY="0" />
</Grid.LayoutTransform>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
make sure to have HorizontalAlignment="Left" VerticalAlignment="Top" in grid otherwise it may appear weird when you zoom.
give it a try and see if this is what you are looking for.
OK guys, here is what needs to be done in order to make it work:
<ItemsControl ItemsSource="{Binding ItemCollection}" Margin="0" Width="{Binding CanvasWidth}"
Height="{Binding CanvasHeight}"/>

How to use an ItemTemplate on a templated control?

I am trying to create custom templated control based on a ListBox to display only the single selected item in the control's collection.
To this aim, I have defined a Template with an ContentPresenter, databound to the SelectedItem property of the control.
As illustrated in scenario 1, it works well when providing the control with a collection of UIElement.
But when needing to use a DataTemplate to display an entity object, the ItemTemplate is ignored because the control has a Template which will prevent the `ItemTemplate from being used. From what I've read this is by design and it sorts of makes sense.
But how can I use DataTemplates for my control's ItemTemplate and retain my control default template?
I have tried overriding PrepareContainerForItemOverride, and many different template configurations to no avail.
Here is some of what I tried:
<UserControl.Resources>
<local:StringCollection x:Key="MyColors">
<sys:String>Yellow</sys:String>
<sys:String>Purple</sys:String>
</local:StringCollection>
</UserControl.Resources>
<StackPanel Background="White">
<TextBlock Margin="0,25,0,0">Scenario 1: Providing UIElements to the
ControlTemplate's ContentPresenter: Works</TextBlock>
<control:RotatingFlipView x:Name="Works" SelectedIndex="1">
<control:RotatingFlipView.Template>
<ControlTemplate>
<ContentPresenter
Content="{Binding ElementName=Works, Path=SelectedItem}"/>
</ControlTemplate>
</control:RotatingFlipView.Template>
<Rectangle Height="100" Width="100" Fill="Red"/>
<Rectangle Height="100" Width="100" Fill="Blue"/>
<Rectangle Height="100" Width="100" Fill="Green"/>
</control:RotatingFlipView>
<TextBlock Margin="0,25,0,0">Scenario 2: The ItemTemplate provided is ignored in
favor of the RotatingFlipView's Template which displays the source as raw
Strings</TextBlock>
<control:RotatingFlipView x:Name="Broken"
ItemsSource="{StaticResource MyColors}">
<control:RotatingFlipView.Template>
<ControlTemplate>
<ContentPresenter
Content="{Binding ElementName=Broken, Path=SelectedItem}"/>
</ControlTemplate>
</control:RotatingFlipView.Template>
<control:RotatingFlipView.ItemTemplate>
<DataTemplate>
<Rectangle Height="100" Width="100" Fill="{Binding}"/>
</DataTemplate>
</control:RotatingFlipView.ItemTemplate>
</control:RotatingFlipView>
<TextBlock Margin="0,25,0,0">Scenario 3: Removing the RotatingFlipView's
Template, causes the display to fall back on the ListBox's Template,
though now my ItemTemplate is used:</TextBlock>
<control:RotatingFlipView x:Name="Broken2"
ItemsSource="{StaticResource MyColors}">
<control:RotatingFlipView.ItemTemplate>
<DataTemplate>
<Rectangle Height="100" Width="100" Fill="{Binding}"/>
</DataTemplate>
</control:RotatingFlipView.ItemTemplate>
</control:RotatingFlipView>
</StackPanel>
RotatingFlipView.cs
public class RotatingFlipView : ListBox
{
public RotatingFlipView()
{
DefaultStyleKey = typeof(RotatingFlipView);
}
}
generic.xaml
<Style TargetType="local:RotatingFlipView">
<Setter Property="SelectionMode" Value="Single"/>
<Setter Property="SelectedIndex" Value="0"/>
</Style>
Output:
I have now figured it out. Here is how I've done it:
Mainpage.xaml
<UserControl.Resources>
<local:StringCollection x:Key="MyColors">
<sys:String>Yellow</sys:String>
<sys:String>Purple</sys:String>
</local:StringCollection>
</UserControl.Resources>
<StackPanel Background="White">
<control:RotatingFlipView>
<Rectangle Height="100" Width="100" Fill="Red"/>
<Rectangle Height="100" Width="100" Fill="Green"/>
<Rectangle Height="100" Width="100" Fill="Blue"/>
</control:RotatingFlipView>
<control:RotatingFlipView ItemsSource="{StaticResource MyColors}">
<control:RotatingFlipView.ItemTemplate>
<DataTemplate>
<Rectangle Height="100" Width="100" Fill="{Binding}"/>
</DataTemplate>
</control:RotatingFlipView.ItemTemplate>
</control:RotatingFlipView>
<StackPanel/>
RotatingFlipView.cs
public class RotatingFlipView : ListBox
{
public RotatingFlipView()
{
DefaultStyleKey = typeof(RotatingFlipView);
}
}
generic.xaml
<Style TargetType="local:RotatingFlipView">
<Setter Property="SelectionMode" Value="Single"/>
<Setter Property="SelectedIndex" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:RotatingFlipView">
<ContentPresenter
Content="{TemplateBinding SelectedItem}"
ContentTemplate="{TemplateBinding ItemTemplate}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Categories