I am trying to get a better understanding of the Templating system with WPF. My design goal here is that I am trying to re-design a component of a software package I work on to use WPF instead of 2D Graphics Librarys. The problem right now is that with 2000 entitys on the screen, pan and zoom is very laggy on a beefy i7 workstation. I wish to redevelop it in WPF to improve performance.
Just as a test, I have created a new project and created a basic XAML/WPF View with a Canvas. This canvas displays ellipses (essentially I am building a 2D Map for planning purposes which has circles of different colors to show different things).
Now, I have my circles showing up fine using a DataTemplate depending on what sort of model the circle is (Circle A or Circle B). When I mouse over the circle, I have the windows default 'blue box' area behind it, which I wish to remove. So far I have managed to use a trigger to change the circle color on mouse over, but I still have the hover area.
<DataTemplate x:Key="HoleBTemplate">
<Grid Width="40" Height="40">
<Ellipse>
<Ellipse.Style>
<Style TargetType="Ellipse">
<Setter Property="Fill" Value="DeepSkyBlue"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Fill" Value="Yellow" />
</Trigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<Ellipse Fill="White" Margin="1" IsHitTestVisible="False" />
<TextBlock
VerticalAlignment="Center"
TextAlignment="Center"
HorizontalAlignment="Center"
Text="{Binding Name}"
IsHitTestVisible="False">
</TextBlock>
<Grid.RenderTransform>
<TranslateTransform X="-20" Y="-20" />
</Grid.RenderTransform>
</Grid>
</DataTemplate>
I created my own ListBox Control which positions the ListBoxItems at an X,Y location inside a canvas.
<controls:ListBoxMap ItemsSource="{Binding Holes}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas></Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplateSelector>
<controls:PlanTemplateSelector
HoleATemplate="{StaticResource HoleATemplate}"
HoleBTemplate="{StaticResource HoleBTemplate}"/>
</ItemsControl.ItemTemplateSelector>
</controls:ListBoxMap>
TLDR: How do I get rid of the blue highlight area behind the circles on mouse over?
Answer from linked thread above, by Wayne Lo.
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding Content.IsSelected, Mode=TwoWay, RelativeSource={RelativeSource Self}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Related
I have this XAML code for a button. I need this button to just be a circle of a solid color.
<Button x:Name="btn_Color" Grid.Column="0" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center" Height="25" Width="25" BorderBrush="Black">
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Fill="Black"/>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
I want this button to change color when I click it, and be able to reuse this code for other buttons. I will use the color later for other things so I need to be able to access that data.
I tried to add a PreviewMouseDown event to the Ellipse and change the property on (Ellipse)sender but I can't access the color of the Ellipse even if I add it a x:Name property. How can I achieve this? Thanks! :)
You can use this code to achieve what you want. It is at least a starting point:
<Button x:Name="btn_Color" Grid.Column="0" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center" Height="25" Width="25">
<Button.Style>
<Style TargetType="Button">
<Setter Property="BorderBrush" Value="Black"/>
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="BorderBrush" Value="Green"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Fill="{Binding BorderBrush, RelativeSource={RelativeSource AncestorType=Button}}"/>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
Doing it this way, you can then Bind the BorderBrush to a different color, or a DependencyProperty and change it from another place.
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.
I am doing a program in WPF that has different rectangles disposed inside a grid. They all have an imagesource binding that makes the image change dynamically throughout the program. It's similar to the 2048. The thing is that now I want to make this rectangle change its imagesource when the mouse is over it. Like I already did an imagesource binding I cant figure out how to do it.
<ListBox Grid.Row="1" ItemsSource="{Binding Tiles}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Background="{Binding Converter={StaticResource BackgroundColor2048Converter}}" Width="106.25px" Height="106.25px" CornerRadius="3" BorderThickness="1" VerticalAlignment="Stretch" Focusable="False" HorizontalAlignment="Stretch" Margin="7">
<Rectangle Width="104.25px" Height="104.25px" MouseEnter="Rectangle_MouseEnter" MouseLeave="Rectangle_MouseLeave" >
<Rectangle.Fill>
<ImageBrush ImageSource="{Binding Converter={StaticResource ImageBackgroundColor2048Converter}, Mode=OneWay}"/>
</Rectangle.Fill>
</Rectangle>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
That's the xaml code regarding the rectangle. The imagesource converter works and is used to change the image during the game. But now I want to change that image too when the mouseenter event triggers. And thats where I am completely lost to, on how to do it.
You do this through a trigger:
<Rectangle Width="104.25px" Height="104.25px" MouseEnter="Rectangle_MouseEnter" MouseLeave="Rectangle_MouseLeave" >
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="Fill" >
<Setter.Value>
<ImageBrush ImageSource="{Binding Converter={StaticResource ImageBackgroundColor2048Converter}, Mode=OneWay}"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Rectangle.IsMouseOver" Value="True">
<Setter Property="Fill" >
<Setter.Value>
<!-- Whatever you want here -->
<ImageBrush ImageSource="{Binding MouseOverImageUri}" />
</Setter.Value>
</Setter>
</Trigger>
</Style>
</Rectangle.Style>
</Rectangle>
Note that you have to set the default value through a style. The reason for this is that triggers override styles, but directly applied attributes override triggers. In this case, you want the trigger to win.
On a WPF app, I got a Canvas object containing several Path object. I need to do things on click on those Path, things that would be in VM. There is no Command on Path, like Button for example. What is the best way to do that?
My solution so far is :
To create an MouseDown handler on the view code behind to catch my Path click
Send a message from here
Register to this message type on targeted VM in order to execute my business code.
It seems a bit overkill to me, what's your opinion? Do you see a more straitforward method?
Thanks a lot !
You can use Button with Path as Template:
<Button Command="{Binding MyCommand}">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Path ... />
</ControlTemplate>
</Button.Template>
</Button>
Just to add complementary infos about my last comment... The right way to position ItemTemplate is to style the ContentPresenter, within ItemsControl.ItemContainerStyle. Below you will find my finally working code :
<UserControl.Resources>
<Style x:Key="PathStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Path Data="{Binding Data}"
StrokeStartLineCap="Round"
Stretch="Fill"
StrokeEndLineCap="Round"
Stroke="{DynamicResource selectedZoneBorderColor}"
StrokeLineJoin="Round"
Width="{Binding Path=Width}"
Height="{Binding Path=Height}"
Fill="{DynamicResource selectedZoneColor}"
Panel.ZIndex="1"
StrokeThickness="3" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<ItemsControl Name="zonesContainer" ItemsSource="{Binding Zones}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Grid.Column="1" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button
Style="{StaticResource ResourceKey=PathStyle}"
Command="{Binding ElementName=zonesContainer,
Path=DataContext.ActivateZone}"
CommandParameter="{Binding Id}"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Path=Left}" />
<Setter Property="Canvas.Top" Value="{Binding Path=Top}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
All this with corresponding VM exposing a ObservableCollection, and a Zone class exposing all inside props (Width, Height, Top, Left...).
You can detailled answer here
I need to extend a slider thumb to stick out of its control. Is that possible then how? If not how can i achieve this? Please Help.
For e.g My slider's height is 50 but the thumb must start -50px outside the control and have 100 height.
Here yellow is the slider control, red is the thumb now I need the thumb to extend add the orange part to the same thumb.
Thanks
If you can build a UI using WPF controls, then you can define a new ControlTemplate... it really is no different. Here is how... always start by implementing the default ControlTemplate so that your object initially looks 'normal'. Then simply locate the part you want to change... and change it:
The trick with this one is that the Thumb does not stick out of the control, instead the whole control is enlarged. Now the default ControlTemplate is so large that I'm not going to add all of the XAML here. Start with the default one that #VimalCK kindly added a link to (don't forget to include the Resources) and then add these changes (hopefully I've remembered all that I changed:
<Style x:Key="SliderThumbStyle" TargetType="{x:Type Thumb}">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="Height" Value="200" />
<Setter Property="Width" Value="14" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Grid>
<Ellipse x:Name="Ellipse" StrokeThickness="1" Height="14"
VerticalAlignment="Bottom">
... <!--Use default XAML here-->
</Ellipse>
<Rectangle Height="200" Width="2" Stroke="Red" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then inside the HorizontalSlider ControlTemplate, change the TrackBackground Border definition to this:
<Border x:Name="TrackBackground" VerticalAlignment="Bottom" Margin="0,0,0,5"
CornerRadius="2" Height="4" Grid.Row="1" BorderThickness="1">
... <!--Use default XAML here-->
</Border>
Then use it with a Height like this:
<Slider Height="210" Maximum="100" Minimum="0" TickPlacement="BottomRight"
VerticalAlignment="Bottom" />
I think I documented all the changes that I made... if not, you might need to set a Height, or a VerticalAlignment to Bottom on something... either way, just experiment until you get what you want. Exploring how the default ControlTemplates have been defined is a great way to learn WPF.
The WPF controls provided by Microsoft has a default style and template which is available in MSDN and you can modify this based on your requirements. For Slider control Style and Template please visit below link
http://msdn.microsoft.com/en-us/library/ms753256(v=vs.110).aspx
Wrap thumb by Canvas Control and set ClipToBOunds= "False" like this
<Style x:Key="SliderThumbStyle"
TargetType="{x:Type Thumb}">
<Setter Property="SnapsToDevicePixels"
Value="true" />
<Setter Property="OverridesDefaultStyle"
Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Canvas>
<Border Width="16" Height="16" Canvas.Top="-3" ClipToBounds="False" Background="Black" />
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>