WPF Template: AdornedElement not showing!

I want to add some elements to a TextBox by using a Template with the extra elements and the original TextBox inserted in the right spot. I'm trying to use the AdornedElementPlaceholder just like you would do when making a Validation.ErrorTemplate But the AdornedElement is not showing up. I have simplified the example as much as possible:

<TextBox Text="Border me with my Template">
     <TextBox.Template>
      <ControlTemplate TargetType="{x:Type TextBox}">
       <Border BorderBrush="Green" BorderThickness="1">
        <AdornedElementPlaceholder/>
       </Border>
      </ControlTemplate>
     </TextBox.Template>
    </TextBox>  

The result is just a green box around the space that should be my textbox!

Answers


Unfortunately, that's just not how it works. However, it's not much more difficult than that. If you want to add a green border around a text box by changing the control template, it's going to look a bit more like this:

<ControlTemplate TargetType="TextBox">
    <Border x:Name="Border"
            CornerRadius="2"
            Background="{TemplateBinding Background}"
            BorderBrush="Green"
            BorderThickness="1"
            SnapsToDevicePixels="True">
        <ScrollViewer x:Name="PART_ContentHost"/>
    </Border>
</ControlTemplate>

The important part in there is the ScrollViewer named PART_ContentHost. The TextBox looks for that guy when the template is applied and uses it to host the text, caret, etc. What I think you're missing is that when you override the Template for an element, you're overriding the entire control template. It's unfortunate that you can't just change bits and pieces, but that's the truth of the matter.

Of course, if you want to maintain the original look and feel of the TextBox, such that it still looks like a Win7 TextBox for instance, you'd need to do a bit more in the ControlTemplate.

For what it's worth, it looks like the template you were trying to apply would work if you're talking about using an Adorner. It's similar to how the validation templates work in WPF, but that's a whole-nother story.

Oh, and for a much simpler way to change the border to green, you should be able to just set the BorderBrush property on the TextBox itself. Of course, I really don't know exactly what you're going for.

-- HTH Dusty


I ended up doing a Custom Control based on a HeaderedContent Control.

It will allow the user to click or hoover over some content and then show a bubble containing some other or the same content.

Usage:

<JsCustomControls:BaloonBox LabelText="{Binding Note}" WaterMark="Click to write Note" Type="ClickToShow">
<JsCustomControls:BaloonBox.Content>
<TextBox AcceptsReturn="True" Text="{Binding Path=Note}" TextWrapping="Wrap"></TextBox>
</JsCustomControls:BaloonBox.Content>
</JsCustomControls:BaloonBox>

The code for the User control:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;

namespace JsCustomControls
{
    public enum BaloonBoxTypeEnum
    {
        ClickToShow,
        MouseOverToShow,
        Manual
    }

    [TemplatePart(Name = BaloonBox.HeaderElement, Type = typeof(ContentPresenter))]
    [TemplatePart(Name = BaloonBox.ContentElement, Type = typeof(ContentPresenter))]
    [TemplatePart(Name = BaloonBox.PopUpElement, Type = typeof(Popup))]
    [TemplatePart(Name=BaloonBox.LabelElement,Type=typeof(Label))]
    public class BaloonBox : HeaderedContentControl
    {
        DispatcherTimer PopupTimer = new DispatcherTimer();

        private const string HeaderElement = "PART_HeaderContentControl";
        private const string ContentElement = "PART_ContenContentControl";
        private const string PopUpElement = "PART_PopUp";
        private const string LabelElement = "PART_HeaderLabel";

        private ContentPresenter headerContentControl;
        private ContentPresenter contentContentControl;
        private Popup popUp;
        private Label headerLabel;

        static BaloonBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(BaloonBox), new FrameworkPropertyMetadata(typeof(BaloonBox))); 
        }
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            headerContentControl = GetTemplateChild(HeaderElement) as ContentPresenter;
            contentContentControl = GetTemplateChild(ContentElement) as ContentPresenter;
            popUp = GetTemplateChild(PopUpElement) as Popup;
            headerLabel = GetTemplateChild(LabelElement) as Label;
            if (headerContentControl != null) headerContentControl.MouseDown += new MouseButtonEventHandler(headerContentControl_MouseDown);
            if(headerLabel!=null)headerLabel.MouseDown+=new MouseButtonEventHandler(headerContentControl_MouseDown);
            if (headerContentControl != null) headerContentControl.MouseMove += new MouseEventHandler(headerContentControl_MouseMove);
            if(headerLabel!=null)headerLabel.MouseMove+=new MouseEventHandler(headerContentControl_MouseMove);
            PopupTimer = new DispatcherTimer();
            PopupTimer.Tick += new EventHandler(PopupTimer_Tick);
            if(string.IsNullOrEmpty(LabelText))
            {
                if (headerLabel != null) headerLabel.Foreground = Brushes.Gray;
                if (headerLabel != null) headerLabel.Content = WaterMark;
            }
            else
            {
                if (headerLabel != null) headerLabel.Foreground = Brushes.Black;
                if (headerLabel != null) headerLabel.Content = LabelText;
            }
        }

        void headerContentControl_MouseMove(object sender, MouseEventArgs e)
        {
            if (Type == BaloonBoxTypeEnum.MouseOverToShow)
            {
                if (popUp != null) popUp.IsOpen = true;
                PopupTimer.Interval = new TimeSpan(0, 0, 0, 2);
                PopupTimer.Start();
            }
        }
        void headerContentControl_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (Type == BaloonBoxTypeEnum.ClickToShow)
            {
                if (popUp != null) popUp.IsOpen = true;
                PopupTimer.Interval = new TimeSpan(0, 0, 0, 3);
                PopupTimer.Start();
            }

        }
        void PopupTimer_Tick(object sender, EventArgs e)
        {
            if (!headerContentControl.IsMouseOver && !contentContentControl.IsMouseOver && !contentContentControl.IsKeyboardFocusWithin)
            {
                PopupTimer.Stop();
                popUp.IsOpen = false;
            }
        }

        public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register("IsOpen",
                                                                                               typeof (bool),
                                                                                               typeof (BaloonBox),
                                                                                               new FrameworkPropertyMetadata
                                                                                                   (new PropertyChangedCallback
                                                                                                        (OnIsOpenChanged)));
        public bool IsOpen
        {
            get { return (bool) GetValue(IsOpenProperty); }
            set{SetValue(IsOpenProperty,value);}
        }

        private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            BaloonBox baloonBox = (BaloonBox)d;
            baloonBox.popUp.IsOpen =(bool)e.NewValue;          
        }

        public static readonly DependencyProperty WaterMarkProperty = DependencyProperty.Register("WaterMark",
                                                                                                  typeof (string),
                                                                                                  typeof (BaloonBox),
                                                                                                  new FrameworkPropertyMetadata
                                                                                                      (new PropertyChangedCallback
                                                                                                           (OnWatermarkChanged)));


        public string WaterMark
        {
            get { return (string)GetValue(WaterMarkProperty); }
            set { SetValue(WaterMarkProperty,value); }
        }

        private static void OnWatermarkChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

        }

        public static readonly DependencyProperty LabelTextProperty = DependencyProperty.Register("LabelText",
                                                                                                  typeof (string),
                                                                                                  typeof (BaloonBox)
                                                                                                  ,new FrameworkPropertyMetadata(new PropertyChangedCallback(OnLabelTextChanged)));

        public string LabelText
        {
            get { return (string) GetValue(LabelTextProperty); }
            set
            {
                SetValue(LabelTextProperty,value);
                headerLabel.Content = value;
            }
        }
        private static void OnLabelTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            BaloonBox baloonBox = (BaloonBox)d;
            if (string.IsNullOrEmpty(e.NewValue.ToString()))
            {
                if (baloonBox.headerLabel != null) baloonBox.headerLabel.Foreground = Brushes.Gray;
                if (baloonBox.headerLabel != null) baloonBox.headerLabel.Content = baloonBox.WaterMark;
            }
            else
            {
                if (baloonBox.headerLabel != null) baloonBox.headerLabel.Foreground = Brushes.Black;
                if (baloonBox.headerLabel != null) baloonBox.headerLabel.Content = e.NewValue;
            }


        }
        public static readonly DependencyProperty BaloonBoxTypeProperty = DependencyProperty.Register(
            "BaloonBoxType", typeof(BaloonBoxTypeEnum), typeof(BaloonBox), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnBaloonBoxTypeChanged)));

        public BaloonBoxTypeEnum Type
        {
            get { return (BaloonBoxTypeEnum) GetValue(BaloonBoxTypeProperty);}
            set { SetValue(BaloonBoxTypeProperty,value);}
        }

        private static void OnBaloonBoxTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //who cares? 
        }
    }
}

                    </Border>
                    <Popup x:Name="PART_PopUp" HorizontalOffset="-50" VerticalOffset="-5" AllowsTransparency="True" IsOpen="False" PopupAnimation="Slide" PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Header}">
                        <Grid Height="150" Width="250" >
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="2"></ColumnDefinition>
                                <ColumnDefinition Width="0.050*"></ColumnDefinition>
                                <ColumnDefinition Width="0.900*"></ColumnDefinition>
                                <ColumnDefinition Width="0.050*"></ColumnDefinition>
                                <ColumnDefinition Width="2"></ColumnDefinition>
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="2"></RowDefinition>
                                <RowDefinition Height="0.300*"></RowDefinition>
                                <RowDefinition Height="0.700*"></RowDefinition>
                                <RowDefinition Height="0.100*"></RowDefinition>
                                <RowDefinition Height="2"></RowDefinition>
                            </Grid.RowDefinitions>
                            <Path Grid.Row="1" Grid.RowSpan="3" Grid.Column="1" Grid.ColumnSpan="3" Data="M79,279 L119,279 135,263 135,279 319,279 319,368.5 78.5,368.5 z" Fill="#FFFDFDB3" Stretch="Fill" Stroke="Black" UseLayoutRounding="False">
                            </Path>
                            <ScrollViewer Grid.Row="2" Grid.Column="2" Grid.RowSpan="1" HorizontalScrollBarVisibility="Auto"  VerticalScrollBarVisibility="Auto">
                                <ContentPresenter x:Name="PART_ContenContentControl" Content="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}"/>
                            </ScrollViewer>
                        </Grid>
                    </Popup>
                </Grid>

            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>


Need Your Help

Flickr API issue - oauth_problem=token_used

api login oauth flickr

I am confused regarding some of my FLICKR API requests. I authorize the user and exchange the authorization for the access token. I can do any API call that requires the signed signature, such as f...

Incorrect syntax error when accessing remote stored procedure

asp.net sql sql-server-2005 sql-server-2008 stored-procedures

StackOverflow - I'm still trying to deploy this site, but with every problem I solve, another arises. Anyways - I've set up the database at my hosting to allow remote connections, and it is running...