WPF: decide where to show the contentPresenter in your User control - wpf

I have a very simple UserControl with some borders and some decorations that react to mouseOver, pressed and some nice things.
I want to allow people to set the content of the text from outside, but when I set the content, the generated content presenter overwrites my whole WPF structure.
This is what I tried so far:
<UserControl tags tags tags>
<!-- This is the only way I found to style the textblock that WPF -->
<!-- generates to encapsulate the content string -->
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<TextBlock Background="Green"
HorizontalAligment="Center"
VerticalAlignment="Center"
Text = "{TemplateBinding Content}"/>
</ControlTemplate>
</UserControl.Template>
<!-- Here my borders and fancy things. I want to add animations -->
<!-- and react to mouseOver and Pressed like a button -->
<Border x:Name="SuperNiceBorder" tag tag tag>
<HERE I WANT THE CONTENTPRESENTER>
</Border>
</UserControl>
Is there a way to tell WPF I want the text set by the user in the Content just there ???

Move all your animations and triggers inside the ControlTemplate.
Replace your TextBlock with a ContentPresenter:
<UserControl x:Class="MySolution.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Border x:Name="MyBorder" Background="Green">
<ContentPresenter
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content = "{TemplateBinding Content}"/></Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="MyBorder" Property="Background" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</UserControl.Template>
</UserControl>
And you can use the UserControl like these examples:
1:
<local:MyControl Content="Test Testing tester"/>
2:
<local:MyControl>
<TextBlock Text="Another test from a TextBlock"/>
</wpfAllPurposesTest:MyControl>

Related

(WPF) How can i fill an Expander-Controltemplate with content?

I'm t trying to create an custom Expander with a Controltemplate. My first question is: Where can I put the content of the Expander (not the text shown on the Expander, the content which turnsd visible if you click the Expander)?
This is my Code in App.xaml:
<Application.Resources>
<ControlTemplate x:Key="FileExpanderButton" TargetType="{x:Type ToggleButton}">
<Image Name="BrowseUsedFiles" Source="F:\AudioNodeGUI_XAML\images\Browse_used_files.jpg">
</Image>
</ControlTemplate>
<ControlTemplate x:Key="FileExpander" TargetType="{x:Type Expander}">
<DockPanel>
<ToggleButton x:Name="ExpanderButton" Template="{StaticResource FileExpanderButton}" OverridesDefaultStyle="True" DockPanel.Dock="Top"/>
<ContentPresenter x:Name="ExpanderContent"
Visibility="Collapsed"
Content="{TemplateBinding Content}"
DockPanel.Dock="Bottom" />
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Setter TargetName="ExpanderContent"
Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Application.Resources>
</Application>
And another question: What exactly does the ContentPresenter? Can I replace it simply with my Content?
Expander is a ContentControl, meaning it contains content (other XAML), but that content is not defined in the control template, it is defined by whoever is using the control.
ContentPresenter is used inside the control template to display that content, just like you appear to be doing.

Custom button user control style overwritten when content is set

I am currently using Blend and some tutorials I found online to try to make my own button user control. Normally, I would just use a custom style and apply it to the controls I want, but I wrote in some dependency properties as well so I decided to write my own user control.
Something that I can't get my head around is how to set the Content property without overwriting the styling of the button control. I thought it might have been my code, but I started brand new with another button and I have the same thing happen - when the Content property is set, the button simply turns white and has black text in the upper left corner.
Here is the XAML code that Blend generated for me:
<UserControl x:Class="MyUI.Controls.MyButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="25" d:DesignWidth="100">
<UserControl.Resources>
<Style x:Key="MyButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle/>
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="True"/>
<Trigger Property="IsDefaulted" Value="True"/>
<Trigger Property="IsMouseOver" Value="True"/>
<Trigger Property="IsPressed" Value="True"/>
<Trigger Property="IsEnabled" Value="False"/>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<Button Content="Button" Height="25" Style="{DynamicResource MyButtonStyle}" Width="100"/>
</Grid>
Now, if I reference the button in my main window like this, it reverts any styling that was done within the user control:
<local:MyButton Content="test" />
What do I need to change in order to make the button accept a different Content tag?
What you need is to connect your UserControl level Content property to your Button level Content property. By default UserControl's Content property is its only child element, which is Grid in your case. You can either create your own Content property or another one with different name. In your UserControl's .cs file:
/// <summary>
/// Interaction logic for MyButton.xaml
/// </summary>
public partial class MyButton : UserControl
{
public new static DependencyProperty ContentProperty =
DependencyProperty.Register("Content", typeof (object),
typeof (MyButton));
public new object Content
{
get { return GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
public MyButton()
{
InitializeComponent();
}
}
On your UnserControl's Xaml:
<Button Content="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
Height="25" Style="{DynamicResource MyButtonStyle}" Width="100"/>
Now Button's Content binds to your UserControl level Content property.

Focus image does not work for first time on Textbox

i want to show a focus image around a text box when it got focus. so i create following style
<Style x:Key="TextBoxFocusVisualStyle">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Image Source="/WPFApp;component/Resources/txtFocus.png" Stretch="Fill" Margin="-8,-6,-8,-6"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and in window xaml file i used this style as following
<TextBox Grid.Column="1" Height="34" Margin="186,48,0,0" Name="txtEmailId" VerticalAlignment="Top" KeyboardNavigation.TabIndex="0" MaxWidth="293" HorizontalAlignment="Left" Width="293" Text="" FocusVisualStyle="{DynamicResource TextBoxFocusVisualStyle}"/>
but problem is that it does not work during loading. When window load then initially focus is on that textbox and at that time it does not show the image .However when i navigate to other textbox (and other control) then it show focus image. and finally when i focus return to that textbox then it display the focus image
so problem is that it does not show focus image first time on when window loaded. Please suggest that where i am wrong.
Consider that FocusVisualStyle applies to a control only when focused by keyboard (TAB key).
This is different from the logical focus that you obtain for example using
Control.SetFocus()
For an overview on Focus have a look at
http://msdn.microsoft.com/en-us/library/aa969768.aspx
A possible workaround for your problem is work with DependencyProperty IsFocused an use Style instead of FocusVisualStyle
<Style x:Key="TextBoxStyle" TargetType="{x:Type Control}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Image Stretch="Fill" Margin="-8,-6,-8,-6" Source="/WPFApp;component/Resources/txtFocus.png" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
And then in the main Window
<TextBox Grid.Column="1" Height="34" Margin="186,48,0,0" Name="txtEmailId"
VerticalAlignment="Top" KeyboardNavigation.TabIndex="0" MaxWidth="293"
HorizontalAlignment="Left" Width="293" Text=""
Style="{DynamicResource TextBoxFocusVisualStyle}" Background="White" />
Hope this heps

Setter in property trigger fails if target property already has an explicit value

I'm currently trying to create a ControlTemplate for the Button class in WPF, replacing the usual visual tree with something that makes the button look similar to the little (X) close icon on Google Chrome's tabs. I decided to use a Path object in XAML to achieve the effect. Using a property trigger, the control responds to a change in the IsMouseOver property by setting the icon's red background.
Here's the XAML from a test app:
<Window x:Class="Widgets.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Style x:Key="borderStyle" TargetType="Border">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="#CC0000"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
<ControlTemplate x:Key="closeButtonTemplate" TargetType="Button">
<Border Width="12" Height="12" CornerRadius="6"
BorderBrush="#AAAAAA" Background="Transparent"
Style="{StaticResource borderStyle}"
ToolTip="Close">
<Viewbox Margin="2.75">
<Path Data="M 0,0 L 10,10 M 0,10 L 10,0" Stroke="{Binding BorderBrush, RelativeSource={RelativeSource FindAncestor, AncestorType=Border, AncestorLevel=1}}" StrokeThickness="1.8"/>
</Viewbox>
</Border>
</ControlTemplate>
</Window.Resources>
<Grid Background="White">
<Button Template="{StaticResource closeButtonTemplate}"/>
</Grid>
</Window>
Note that the circular background is always there - it's just transparent when the mouse isn't over it.
The problem with this is that the trigger just isn't working. Nothing changes in the button's appearance. However, if I remove the Background="Transparent" value from the Border object in the ControlTemplate, the trigger does work (albeit only when over the 'X').
I really can't explain this. Setters for any other properties placed in the borderStyle resource work fine, but the Background setter fails as soon as the default background is specified in the ControlTemplate.
Any ideas why it's happening and how I can fix it? I know I could easily replace this code with, for example, a .PNG-based image, but I want to understand why the current implementation isn't working.
Thanks! :)
Try moving the explict "Background" assignment from inside the Border declaration to the Style itself:
<Style x:Key="borderStyle" TargetType="Border">
<Setter Property="Background" Value="Transparent" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="#CC0000"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
...
<Border Width="12" Height="12" CornerRadius="6"
BorderBrush="#AAAAAA"
Style="{StaticResource borderStyle}"
ToolTip="Close">
Styles can't override a property that has been explicitly set. You need to set the value in the style.
I think your problem is that the Border does not 'catch' the mouse events when it is transparant.
To verify - try changing the background to #01FFFFFF instead of Transparent.

how do i make that dang wpf popup go away?

when i use a popup, it seems to hang around. in the code below i attach a popup to a textBox using by overriding the control template, and make the popup appear when the TextBox has focus. When you tab to the next on screen element the popup goes away, but if you just alt-tab to a different application the popup stays there in the foreground. how do i get rid of it?
<Window x:Class="DropDownPicker.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<StackPanel>
<TextBox Text="hello">
<TextBox.Style>
<!-- Simple TextBox -->
<Style
TargetType="{x:Type TextBox}">
<Setter
Property="KeyboardNavigation.TabNavigation"
Value="None" />
<Setter
Property="FocusVisualStyle"
Value="{x:Null}" />
<Setter
Property="AllowDrop"
Value="true" />
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type TextBox}">
<Grid>
<Border
x:Name="Border"
Background="{DynamicResource WindowBackgroundBrush}"
BorderBrush="{DynamicResource SolidBorderBrush}"
BorderThickness="1"
Padding="2"
CornerRadius="2">
<Grid>
<!-- The implementation places the Content into the ScrollViewer. It must be named PART_ContentHost for the control to function -->
<ScrollViewer
Margin="0"
x:Name="PART_ContentHost"
Style="{DynamicResource SimpleScrollViewer}"
Background="{TemplateBinding Background}" />
<Popup
x:Name="thePopup"
IsOpen="False">
<Border
BorderBrush="Red"
BorderThickness="5">
<TextBlock
Text="Hellssss" />
</Border>
</Popup>
</Grid>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger
Property="IsFocused"
Value="True">
<Setter
TargetName="thePopup"
Property="IsOpen"
Value="True" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TextBox.Style>
</TextBox>
<TextBox
Text="ssss" />
</StackPanel>
</Grid>
</Window>
Have you tried setting the StaysOpen property to False?
If StaysOpen is True, which is the default, it will stay open until the control is no longer in focus. If it is False it will stay open until a mouse or keyboard event occurs outside of the Popup control, which may be the case while alt-tabing. You might have to tweak it a bit to get it to behave like you want, but it may be a starting point.
I listened to the LostMouseCapture event and then set the StaysOpen property on the Popup to false
This is by-design; Window focus != Control focus, otherwise when you tabbed away from a window and came back, your cursor would jump back to the first control. If you want the pop up to be hidden when the window isn't active, you have to manually do this.
Similar question is asked here also:
WPF Popup ZOrder
Check this:
http://chriscavanagh.wordpress.com/2008/08/13/non-topmost-wpf-popup/
Hope this help you!!

Resources