distance between items in listview datatemplate wpf - c#

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.

Related

ContentPresenter steals resources?

In a simple view I want to display two buttons, that have as contents images, that are provided via resources in an extra style.xaml that is loaded in the App.xaml.
<BitmapImage x:Key="AddIcon" UriSource="pack://application:,,,/WpfTestBench;component/Images/plus.png"></BitmapImage>
<BitmapImage x:Key="RemoveIcon" UriSource="pack://application:,,,/WpfTestBench;component/Images/minus.png"></BitmapImage>
<Style x:Key="AddButtonWithIconStyle" TargetType="{x:Type Button}">
<Setter Property="Content">
<Setter.Value>
<Image Source="{DynamicResource AddIcon}" Stretch="None"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="RemoveButtonWithIconStyle" TargetType="{x:Type Button}">
<Setter Property="Content">
<Setter.Value>
<Image Source="{DynamicResource RemoveIcon}" Stretch="None"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Setter.Value>
</Setter>
</Style>
In my view I use the styles like this:
<DockPanel Margin="0,0,5,0" DockPanel.Dock="Bottom" LastChildFill="False" >
<Button Command="{Binding DeleteCommand}" DockPanel.Dock="Right"
Style="{StaticResource RemoveButtonWithIconStyle}"/>
<Button Command="{Binding AddCommand}" DockPanel.Dock="Right" Margin="5,0"
Style="{StaticResource AddButtonWithIconStyle}"/>
</DockPanel>
So far this looks good.
But when I add another view into this view via a ContentPresenter, that has basically the same content (again with the above described button styles) the display of the first two buttons (of the parent view) does not work anymore. All I get ist two small circles with the button functionality.
<ContentPresenter Content="{Binding SomeEmbeddedViewModel, UpdateSourceTrigger=PropertyChanged}"/>
Why does this happen? Does the ContentPresenter somehow prevent to share the resources?
As explained in the other answer, you should have the Image control in the ContentTemplate of the Button.
Declare a simple Image Button Style with an Image that has its Source property bound to the actual Content:
<Style x:Key="ImageButtonStyle" TargetType="Button">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
...
<Button Style="{StaticResource ImageButtonStyle}"
Content="{DynamicResource RemoveIcon}" .../>
You may also declare the Style as default Button Style, probably inside the DockPanel:
<DockPanel>
<DockPanel.Resources>
<Style TargetType="Button">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{Binding}" Stretch="None"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DockPanel.Resources>
<Button Command="{Binding DeleteCommand}" DockPanel.Dock="Right"
Content="{DynamicResource RemoveIcon}"/>
<Button Command="{Binding AddCommand}" DockPanel.Dock="Right" Margin="5,0"
Content="{DynamicResource AddIcon}"/>
</DockPanel>
Diagnosis
The core reason of this behavior is that an element can only appear once in the visual tree.
First of all, resources in a ResourceDictionary are by default shared, i.e. every time you fetch a resource with a particular key, you always get the same instance. In your case, you always get the same instance of Style, which also means that there's always only one instance of Image (for each style).
So if you apply the same style to two buttons, the framework tries to put the same Image instance in two different places, which is not allowed. To avoid that, upon attempt to load the image into the visual tree, if it already is in the visual tree, it is unloaded from the previous location first.
That's why the image is only visible in the last button (in order in which they were loaded).
Solution
There are basically two solutions to this problem.
1. Disable resource sharing
You can disable the resource sharing so that each time you fetch a resource from a ResourceDictionary you get a new instance of the resource. In order to do that, you set x:Shared="False" on your resource:
<Style x:Key="AddButtonWithIconStyle" x:Shared="False" TargetType="{x:Type Button}">
(...)
</Style>
2. Use ContentTemplate in your style
Instead of putting the image as the content of the button, you could define a ContentTemplate, which is realized separately for each button it is applied to (so each button gets its own instance of the image):
<Style x:Key="RemoveButtonWithIconStyle" TargetType="{x:Type Button}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{DynamicResource RemoveIcon}" Stretch="None"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Personally I'd advise you to use the second solution, since that's exactly the purpose of templates in WPF.

Enlarge an image on mouseover in Popup in WPF

Hi all I've looked through several of these forum posts with different solutions but can't seem to get it. My style
<Style x:Key="ScaleStyle" TargetType="Image">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Grid.ZIndex" Value="1"/>
<Setter Property="RenderTransform">
<Setter.Value>
<ScaleTransform ScaleX="2.5" ScaleY="2.5"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
My UniformGrid with images:
<ListView Grid.ColumnSpan="5" Grid.Row="11" Name="Thumbnails">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="5"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Image Style="{StaticResource ScaleStyle}" RenderTransformOrigin="0.5,0.5" Source="{Binding}" Height="100" Width="100" Margin="3">
</Image>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
What happens with this is that the image gets bigger but inside the uniform grid which makes it overlap with other images and is just not nice looking.
On the other hand I tried using a tooltip popup and it would open a new popup but the image inside would be a giant zoom of the corner of the image.
<Image Name="Image" Source="/WpfApplication1;component/Images/Tulips.jpg" Height="100"
Stretch="Uniform">
<Image.ToolTip>
<ToolTip DataContext="{Binding PlacementTarget,
RelativeSource={RelativeSource Self}}">
<Border BorderBrush="Black" BorderThickness="1" Margin="5,7,5,5">
<Image Source="{Binding Source}" Stretch="None" />
</Border>
</ToolTip>
</Image.ToolTip>
The problem might be that the original images are very large and in the Uniform grid i set the width and height to a 100 which makes them look like thumbnails but the tooltip seems to reference the original width and height and starts from a corner until it fits the width and height of the tooltip popup which ends up just showing a small part of the original very large picture.
Any help would be greatly appreciated.
Setting the Stretch property of the image to fill will make your image resize to the size of your container.

WPF ProgressBar Width not sizing to Text

I am having an issue with the Microsoft WPF ProgressBar. I will set Width="Auto" and the width will size to the text width until a value property of ~97. Between values 97 and 100 the control will go exponentially larger until it hits MaxWidth.
The following style is setting the template for the ProgressBar. I can't seem to find anything that will cause it to behave until a Value of ~97. I do not touch the width in the code behind.
<Style x:Key="CurrentDayProgressBar" TargetType="{x:Type ProgressBar}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ProgressBar}">
<Grid>
<Border Name="PART_Track" CornerRadius="2" Background="DarkGray" BorderBrush="{DynamicResource TextBrush}" BorderThickness="1" />
<Border Name="PART_Indicator" CornerRadius="2" Background="{DynamicResource ProgressBarBackground}" HorizontalAlignment="Left" Margin="2" />
<TextBlock Name="PART_Text" Margin="2" Width="Auto" Padding="5,0,5,0" Text="{Binding RelativeSource={RelativeSource AncestorType=ProgressBar}, Path=Tag}"
Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{DynamicResource SimpleTextBlock}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The first image below is what the bar looks like when it is at a Value of 99.2. The second is my implementation in the Telerik RadProgressBar, which behaves like I expect it to. The Telerik solution may be what I have to go with, but it would be nice to know why the Microsoft control is not working.
WPF ProgressBar Control
Telerik RadProgressBar and Textbox
The PART_Track cannot have any extra margins/borders attached to it and/or the PART_Indicator should be nested inside it. To resolve the problem you're having, do something like:
<Border CornerRadius="2" Background="DarkGray" BorderBrush="{DynamicResource TextBrush}" BorderThickness="1" />
<Border x:Name="PART_Track" Margin="3">
<Border Name="PART_Indicator" CornerRadius="2" Background="{DynamicResource ProgressBarBackground}" HorizontalAlignment="Left" />
</Border>
<TextBlock ... />

Shapes don't appear to be reacting to setting ZIndex?

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?

Overriding Button in XAML WPF with ControlTemplate does not display content

I am a XAML newbie and was looking at this blog
http://jeremybytes.blogspot.com/2009/03/wpf-xaml-sample.html
He mentions "Notice that they do not have any content (Button1a, Button1b, etc.). This is because our template does not contain an element for the Content." I am looking to figure out how ensure the content remains even after the new button template is applied. Here is the XAML
<Page.Resources>
<ControlTemplate TargetType="Button" x:Key="targetButton">
<Canvas Width="100" Height="100" Name="mainCanvas">
<Rectangle Height="100" Width="100" Fill="Aqua" Canvas.Top="1"/>
</Canvas>
</ControlTemplate>
<Style TargetType="Button">
<Setter Property="Margin" Value="5, 5, 5, 5"/>
<Setter Property="Template" Value="{StaticResource targetButton}"/>
</Style>
</Page.Resources>
<StackPanel DataContext="{Binding Board}">
<StackPanel Orientation="Horizontal">
<Button Name="testButton1a" Click="testButton1a_Click" Content="testButton1a"/>
<Button Name="testButton1b" Click="testButton1a_Click" Content="testButton1b"/>
<Button Name="testButton1c" Click="testButton1a_Click" Content="testButton1c"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Button x:Name="testButton2a" Click="testButton1a_Click" Content="testButton2a"/>
<Button x:Name="testButton2b" Click="testButton1a_Click" Content="testButton2b"/>
<Button x:Name="testButton2c" Click="testButton1a_Click" Content="testButton2c"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Button Name="testButton3a" Click="testButton1a_Click" Content="testButton3a"/>
<Button Name="testButton3b" Click="testButton1a_Click" Content="testButton3b"/>
<Button Name="testButton3c" Click="testButton1a_Click" Content="testButton3c"/>
</StackPanel>
</StackPanel>
I have tried to add a TextBlock in the template but I see the same textblock overlayed across all buttons. All I want is to render testButton* content displayed on the rectangle button matrix so I can change the content once clicked.
Thanks, any help will be appreciated
You can use the ContentPresenter to display the content:
<ControlTemplate TargetType="Button" x:Key="targetButton">
<Canvas Width="100" Height="100" Name="mainCanvas">
<Rectangle Height="100" Width="100" Fill="Aqua" Canvas.Top="1"/>
<ContentPresenter/>
</Canvas>
</ControlTemplate>

Categories