I have PortItem which derived from ContentControl, TextedStackPanel derived from StackPanel which contains PortItems. And in MainWindow i have 2 StackPanels which contains TextedStackPanels . In PortItem i have overridden MouseLeftButtonDown method. But when i do this on this method isn't fired. I searched here in the forum, and found that Background property of Grid/StackPanel must be set to Transparent. I applied this, but there is no changes. What to do ?
EDIT 1
I use partial classes. I have 2 classes: PortItem.cs and PortItem.cs.xaml. I modifiy any visual changes in this XAML file.
EDIT 2
Also any mouse events aren't fired. Triggers which i use IsMouseOver are also dont work when i keep mouse on PortItem
XAML
<ContentControl x:Class="**.PortItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:UI="clr-namespace:**.UIData" Width="17" Height="17" Margin="3" SnapsToDevicePixels="True" >
<Grid Background="Transparent" Name="mainGrid">
<!-- transparent extra space makes connector easier to hit -->
<Rectangle Fill="Transparent" Margin="-2"/>
<Border BorderBrush="Green" x:Name="border" BorderThickness="2">
<Border.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid}, Path=IsMouseOver}" Value="True">
<Setter Property="Border.BorderBrush" Value="Blue"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter Property="Border.BorderBrush" Value="Blue"/>
</DataTrigger>
<!--<DataTrigger Binding="{Binding ContactPort}" Value="{x:Null}">
<Setter TargetName="border" Property="Border.BorderBrush" Value="Green"/>
</DataTrigger>-->
</Style.Triggers>
</Style>
</Border.Style>
<Image Source="/**;component/Resources/1337238611_port.png">
</Image>
</Border>
</Grid>
Make sure that you haven't set 'IsHitTestVisible' to false on your PortItem. Also, make sure no other controls are on top of it. If they are, set their 'IsHitTestVisible' property to false and then your PortItem control will get the mouse right click event. To make sure nothing is on top, declare your put your PortItem as the last thing added to your TextedStackPanel. To double check that nothing else is on top, change the background color of other controls to something really noticeable (just for testing) to see if anything is covering your PortItem control. Also, change the color on your PortItem control to verify that it is really where you think it is. Then once you get it all working, change the colors back to their original colors.
If you could give us a code sample of your XAML, that might help. If you're adding the PortItems dynamically in code behind, supply that code too.
Edit: in light of the changes you've made to your code, try to add ClipToBounds="False" to the top of your user control declaration.
<ContentControl x:Class="**.PortItem" ClipToBounds="False"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:UI="clr-namespace:**.UIData" Width="17" Height="17" Margin="3" SnapsToDevicePixels="True" >
Have you created a template for your PortItem? I created the follow class to replicate your PortItem and break point on the base.OnMouseButtonDown line and it fires, I think the reason your method is not executing is because there is no visual element for the mouse to actually interact with, try adding the style below to your app and you should see the method fire properly.
public class PortItem: ContentControl
{
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
}
}
then in XAML I created a style to give it something to render.
<local:PortItem Margin="44,36,156,95">
<local:PortItem.Style>
<Style TargetType="{x:Type local:PortItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:PortItem}">
<Border Background="Transparent">
<ContentPresenter Content="{TemplateBinding Content}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</local:PortItem.Style>
</local:PortItem>
The background being Transparent that you mention you can see in the border control, if you leave the background out you are correct, the event never fires.
Related
I've this code in C# to create a button as a child of a StackPanel:
`
Button myButton = new Button();
//All button stuff (Background, text...).
myStackPanel.Children.add(myButton);
`
But, as every button, it highlights every time the mouse is over or when I click it. Is there any way to change that in an easy code (I'm still new to C#) can remove that highlight.
I don't know how to do this. I haven't seen anything explaining this and the only codes I could find were in XAML, and I didn't understand them so couldn't translate them to C#.
The problem is all the code I find is about retemplating the XAML code. What I need is to do what I mentioned in C#, as the control is created from scratch in C#.
I took a look at a few of the answers for this and didn't see any I liked much.
WPF controls are lookless, meaning they have fixed behaviour but not specific look to them. You can re template a wpf control to pretty much anything you can describe in xaml. Many wpf controls have quite complicated templates.
Here's one way to template a button as described.
I've put this style in my window's resources. Usually such styles are in resource dictionaries which are merged in app.xaml.
<Window.Resources>
<Style x:Key="NoMouseOverButtonStyle" TargetType="{x:Type Button}">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Border"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}" >
<ContentPresenter Margin="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
RecognizesAccessKey="True" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Button Style="{StaticResource NoMouseOverButtonStyle}"
Content="This is my Button"
Click="Button_Click"
HorizontalAlignment="Left"
VerticalAlignment="Top"
/>
</Grid>
</Window>
The button references the style as a resource.
That style sets some defaults so the button has a border you can see but over ride.
The contentpresenter is critical because this is where whatever you make content of your button will appear.
If I set an actual value on a button then that will over ride the style.
Hence
<Button Style="{StaticResource NoMouseOverButtonStyle}"
Content="This is my Button"
Click="Button_Click"
HorizontalAlignment="Left"
VerticalAlignment="Top"
BorderBrush="Red"
/>
Gives me a red border on my button.
A lightgray border is rather simpler than a button has by default.
You could reproduce that. Maybe that'd be an interesting learning exercise.
Lookup the button template on msdn.
Google: "wpf button template msdn"
Take a look at that. Brace yourself - it is complicated.
See the button border brush is hard coded in the template?
Change the style above so it does the same.
Clue:
<Setter.Value>
So, I've got a custom WPF control called WatermarkTextbox which extends TextBox. The only thing I added to the code is a string dependency property to hold the watermark text. The rest of the magic is in the Xaml (below).
<Style TargetType="wpfControls:WatermarkTextbox" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type wpfControls:WatermarkTextbox}">
<Grid>
<TextBox x:Name="baseTextBox" />
<TextBlock Margin="5,0,0,0" x:Name="watermarkText" IsHitTestVisible="False" FontWeight="Light" FontStyle="Italic" Foreground="DarkGray" Visibility="Hidden" Background="Transparent"
Text="{Binding RelativeSource={RelativeSource AncestorType=wpfControls:WatermarkTextbox}, Path=Watermark}" />
</Grid>
<ControlTemplate.Triggers>
<Trigger SourceName="baseTextBox" Property="Text" Value="">
<Setter TargetName="watermarkText" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and when used in my application:
<wpfControls:WatermarkTextbox Watermark="Text that disappears."/>
This works, mostly. I can set the watermark text, and when I start entering some text, it goes away. When I change the font size, it changes both the watermark and the text I enter; when I change the font weight, it only changes the text entered (which is what I want it to do). I can change the size of the textbox. That's all gravy.
The problem is when I start trying to change things like the textbox's background or border properties, like so.
<wpfControls:WatermarkTextbox Watermark="Text that disappears." Background="Yellow"/>
Nothing happens. Same behavior with BorderBrush and BorderThickness. Now, the part where I know just enough to know that there's some important concept that I don't know. If I change the template for my WatermarkTextbox to the following, it will let me set the background in my application like I want.
<Style TargetType="wpfControls:WatermarkTextbox" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type wpfControls:WatermarkTextbox}">
<Grid>
<TextBox x:Name="baseTextBox"
Background="{TemplateBinding Background}"/>
<TextBlock Margin="5,0,0,0" x:Name="watermarkText" IsHitTestVisible="False" FontWeight="Light" FontStyle="Italic" Foreground="DarkGray"
Text="{Binding RelativeSource={RelativeSource AncestorType=wpfControls:WatermarkTextbox}, Path=Watermark}" Visibility="Hidden" Background="Transparent"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger SourceName="baseTextBox" Property="Text" Value="">
<Setter TargetName="watermarkText" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I assume that if I did the same for BorderBrush and BorderThickness, they would work as well.
So, my question is, why? What is it about these properties that makes them behave differently from FontSize and FontWeight or Height and Width? Why do I have to explicitly set the Background to {TemplateBinding Background} but not FontSize? Also, what other properties do I need to set to the TemplateBinding in order to make them work properly?
Some of the properties are inherited from their parent automatically. explanation
This is why you don't have to set FontSize.
As for "what else", it all depends on what you want to be able to set directly on the user control.
Although this isn't bullet proof, but my general rule of thumb is "if it is a property in the Brush Tab of the property window or is purely for visual aesthetics, it probably is not inherited"
Another way to look at it - if the setting would give weird results in general, it also is probably no inherited. Example: if you set the Margin property on a Grid, imagine if every sub-element inherited the same margins.
So i typically add the template bindings for all the non-Layout, visual properties (Background, Foreground, BorderBrush, etc.). Or i just add templatebindings for any properties i want to set directly to my usercontrol. There is no need to add a template binding if you never intend to set the property (explicitly or by style).
The font properties are inherited attached properties; they're an explicit special case. Incidentally, TextElement.Foreground is one of those.
Height and Width aren't inherited, but you've got XAML there that'll size to its parent by default, and you haven't done anything to disable that behavior.
Anything else, you need to explicitly do the TemplateBinding thing -- or if they'll change at runtime, you'll need to do a relativesource binding:
{Binding PropertyName, RelativeSource={RelativeSource TemplatedParent}}
There isn't any "first principles" explanation for this; it's all just arbitrary implementation details.
I've written a user control with popup, who's content is being set outside the control. The ControlTemplate of that control looks like the following:
<ControlTemplate TargetType="local:InfoIcon">
<Grid>
<ToggleButton x:Name="HelpButton" Style="{StaticResource HelpButton}" />
<Popup PlacementTarget="{Binding ElementName=HelpButton}" Placement="Bottom"
IsOpen="{Binding ElementName=HelpButton, Path=IsChecked, Mode=TwoWay}" StaysOpen="False">
<Border BorderBrush="#767676" BorderThickness="1"
Background="#f1f2f7">
<Border.Resources>
<!-- Important -->
<Style TargetType="Label">
<Setter Property="Foreground" Value="#575757" />
</Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="#575757" />
</Style>
<!-- /Important -->
</Border.Resources>
<ContentPresenter Content="{TemplateBinding HelpContent}" />
</Border>
</Popup>
</Grid>
</ControlTemplate>
The Important part - I want to assign custom styles to items, which are being put inside the popup (it serves as a clickable hint)
I'm using my control in the following way:
<local:MyControl>
<local:MyControl.HelpContent>
<TextBlock>Ala ma kota</TextBlock>
</local:MyControl.HelpContent>
</local:MyControl>
But despite styles in the Border, TextBlock's text's color always inherit the value from its parent (checked using Snoop) - resulting in white text on white background.
You can downlad the small PoC application, which demonstrates the problem.
My observations:
The styling does work for Label. It only doesn't work for TextBlock.
When I add TextBlock.Foreground="Red" to the Border, TextBlock becomes red, still ignoring style (but now using color from Border).
Snoop informs, that this TextBlock actually has the Style resolved correctly. But despite it shouldn't, it uses the inherited value instead of one specified in the style.
How can I solve this problem and why does it occur?
I received answer on Microsoft forums; I'll leave it here in case someone encounters the same problem.
The difference is that a TextBlock is not a control, i.e. it doesn't have any ControlTemplate and because of this the implicit style doesn't get applied to it when it is located inside the StackPanel. Please see the following page for more information: http://blogs.msdn.com/b/wpfsdk/archive/2009/08/27/implicit-styles-templates-controls-and-frameworkelements.aspx
You could use Label elements or set the style for the TextBlock elements explicitly.
-- Magnus (MM8)
Edit2
I've set the Foreground of the UserControl to something else. This behavior is because the child TextBlock controls of the UserControl inherit the Foreground-Settings somehow. This has nothing to do with the popup or some other approaches we tried yet.
I've stumbled upon another question with a similar problems here: Cannot override controls foreground colour in wpf
I suggest to accept this strange behavior and just set a Foreground Color of the UserControl instead:
<Style TargetType="{x:Type local:InfoIcon}">
<Setter Property="Foreground" Value="Red"/>
</Style>
previous Edit
You had my curiousity with this weird behavior, but after looking at your PoC it was rather obvious :) The Popup has some attached Properties TextElement.* where you can style the text elements in the popup. This was new to me, too and I will reseach a bit more afterwards. Nevertheless: Workaround for your Problem is to not style the TextBlock but the Popup instead. your code could look something like following :
<ControlTemplate TargetType="{x:Type local:InfoIcon}">
<ControlTemplate.Resources>
<Style TargetType="Popup">
<Setter Property="TextElement.Foreground" Value="Red"/>
</Style>
<Style TargetType="Label">
<Setter Property="Foreground" Value="Red" />
</Style>
</ControlTemplate.Resources>
<Grid>
<ToggleButton x:Name="TB" Width="16" Height="16"/>
<Popup Placement="Bottom" PlacementTarget="{Binding ElementName=TB}" IsOpen="{Binding ElementName=TB, Path=IsChecked}" StaysOpen="False">
<ContentPresenter Content="{TemplateBinding InfoContent}"/>
</Popup>
</Grid>
</ControlTemplate>
I changed the styles to be outside of the controls, of course you can just use the attached properties of the popup directly. But initially you wanted to know how it works with the styles attached at the border, it does not matter now where you add the styles. You can use a ResourceDictionary for example.
As a suggestion, shouldn't this:
TargetType="local:InfoIcon"
be like this?
TargetType="{x:Type local:InfoIcon}"
Maybe you have some TextBlock style defining that it shouldd take the parent's control foreground.
Did you try to add a BasedOn property like this ?
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="Foreground" Value="#575757" />
</Style>
I tried with your code example and this works :
<ContentPresenter Content="{TemplateBinding InfoContent}">
<ContentPresenter.Style>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="TextBlock.Foreground" Value="Red" />
</Style>
</ContentPresenter.Style>
<ContentPresenter.Resources>
<Style TargetType="{x:Type Label}">
<Setter Property="Foreground" Value="Red" />
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
That's kind of odd because when I put the Foreground setter for the Label control inside the ContentPresenter.Style then this time it's Label wich doesn't work...I think it's because Label is a considered as a ContentControl whereas TextBlock is just a FrameworkElement.
Had a similar issue caused by another problem:
There is a strange bug in WPF that prevents styles, defined in merged dictionaries, from being applied to the first element:
https://www.engineeringsolutions.de/wpf-fix-style-is-only-applied-to-first-element/
I have an Image control on my WPF Form. How can I create a border around it during runtime?
Here's my XAML code:
<Image Margin="2.5"
Grid.Column="1" Grid.Row="0"
x:Name="Behemoth" Source="Images/Hero/Behemoth.gif" Stretch="Fill"
MouseEnter="HeroMouseEnter"
MouseLeave="HeroMouseLeave"
MouseDown="HeroMouseClick" />
Also, I want to know how to remove the border.
Maybe if I state my problem better there is an even better solution available.
I have many Images, and when a user says: "Hey, just show me the woman out of all the picture." I want a way to sort of highlight or draw the users attention to whatever images I need them to see. I was thinking about adding a border, but maybe that's too much work for something that can be solved easier.
Any help?
Although it's visually very different from a border, you could use an outter glow to signify the importance of the image. Then, you don't have to change the parent of the image.
Alternatively, you could use a custom Adorner to place a border around the image. Good info on Adorners can be found on msdn.
There's no straightforward way to do it, because the Border is a container, so you would have to remove the Image from its parent, put the Border instead, and put the Image back in the Border...
Another option would be to use templates :
<Window.Resources>
<ControlTemplate x:Key="imageWithBorder" TargetType="{x:Type Image}">
<Border BorderBrush="Red" BorderThickness="2">
<Image Source="{TemplateBinding Source}" />
</Border>
</ControlTemplate>
</Window.Resources>
...
<Image Name="image1" Source="foo.png"/>
When you want to put the border around the image, just assign the template to the image :
image1.Template = this.FindResource("imageWithBorder") as ControlTemplate;
For your stated needs, I suggest you use a ListBox with a custom ItemContainerStyle - one that always has a border but only makes it visible if the item is selected.
Here's the basic idea:
<ListBox ItemsSource="{Binding MyImageObjects}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="border">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="ListBoxItem.IsSelected" Value="True">
<Setter ElementName="border" Property="BorderBrush" Value="Blue" />
<Setter ElementName="border" Property="BorderThickness" Value="2" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
I have the following code in the Window.Resources of a WPF window. What it is basically doing is creating an item that represents a grid with a label positioned on the left and a button on the right. When I mouse over the label or the button the row changes color as expected but I want it to also change color if the mouse is over any of the row.
How can this be achieved?
Any help is appreciated.
<Window.Resources>
<dtos:ProjectDto x:Key="data"/>
<Style x:Key="alternatingWithTriggers"
TargetType="{x:Type ContentPresenter}">
<Setter Property="Height" Value="25"></Setter>
</Style>
<Style x:Key="onmouseover" TargetType="{x:Type DockPanel}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Yellow">
</Setter>
</Trigger>
</Style.Triggers>
</Style>
<DataTemplate x:Key="ItemTemplate">
<Border x:Name="ItemBorder" HorizontalAlignment="Stretch" BorderThickness="0" Background="#BBB" ClipToBounds="True" >
<DockPanel ClipToBounds="True" HorizontalAlignment="Stretch" Style="{StaticResource onmouseover}">
<Label Content="{Binding Name}" HorizontalAlignment="Left" Height="80"></Label>
<Button Content="Delete" HorizontalAlignment="Right" Margin="0,0,10,0"/>
</DockPanel>
</Border>
...
Give the DockPanel Background="Transparent". That should allow it to capture mouse events.
I don't see anything obviously wrong in the snippet you've posted, and since I'm not in front of Studio, I can't try it out, but if I were you, I'd try adding a MouseEnter handler on the DockPanel (just throw the do-nothing handler in the code-behind for the view, since you'll remove it later).
Make sure that handler is getting hit when you enter, and with the debugger/immediate window, make sure the IsMouseOver property is as you expect it to be. That will at least direct your next debugging steps:
If IsMouseOver is true and your handler is hit, then my guess would be something about the trigger you've got set up isn't quite right.
If IsMouseOver is false or your handler isn't hit, then my guess would be something like IsHitTestVisible is set to false or something of that sort.
Just for fun, I'd also try moving the style declaration inline to the dockpanel, just to make sure, like so:
<DataTemplate x:Key="ItemTemplate">
<Border x:Name="ItemBorder" HorizontalAlignment="Stretch" BorderThickness="0" Background="#BBB" ClipToBounds="True" >
<DockPanel ClipToBounds="True" HorizontalAlignment="Stretch">
<DockPanel.Style>
<Style TargetType="{x:Type DockPanel}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Yellow"/>
</Trigger>
</Style.Triggers>
</Style>
</DockPanel.Style>
<Label Content="{Binding Name}" HorizontalAlignment="Left" Height="80"></Label>
<Button Content="Delete" HorizontalAlignment="Right" Margin="0,0,10,0"/>
</DockPanel>
</Border>