tags:

views:

939

answers:

5

Is it possible to change or modify a specific part of a control template without having to recreate the entire control template of the control in the xaml?

For example, I was trying to get rid of the border of a textbox, so I could throw together a basic search box with rounded corners (example xaml below). Setting the borderthickness to 0 works fine, until you mouse over the textbox and a pseudo border they added to the control flashes up. If I look at the controltemplate for the textbox, I can even see the visual state is named, but cannot think of how to disable it.

Without overriding the control template of the TextBox, how would I stop the Visual State Manager firing the mouse over effect on the TextBox?

<Border Background="White" CornerRadius="10" VerticalAlignment="Center" HorizontalAlignment="Center" BorderThickness="3" BorderBrush="#88000000">
    <Grid VerticalAlignment="Center" HorizontalAlignment="Center" Width="200" Margin="5,0,0,0">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="16" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Path Height="13" Width="14" Stretch="Fill" Stroke="#FF000000" StrokeThickness="2" Data="M9.5,5 C9.5,7.4852815 7.4852815,9.5 5,9.5 C2.5147185,9.5 0.5,7.4852815 0.5,5 C0.5,2.5147185 2.5147185,0.5 5,0.5 C7.4852815,0.5 9.5,2.5147185 9.5,5 z M8.5,8.4999971 L13.5,12.499997" />
            <TextBox GotFocus="TextBox_GotFocus" Background="Transparent" Grid.Column="1" BorderThickness="0" Text="I am searchtext" Margin="5,0,5,0" HorizontalAlignment="Stretch" />
    </Grid>
</Border>
+2  A: 

Its been awhile since I used XAML, but no, I don't believe you can just modify a piece of the template.

However if you have the IDE you can create a copy of the currently applied template and just modify the piece you want and leave the rest as is. See the How to Edit section of this link.

Brandon
That's precisely what I'm trying to avoid having to do :) It just feels like a cut 'n paste disaster waiting to happen!
mattmanser
Unfortunately, I think that this is the only way as it applies the template as a whole and not just individual pieces. Although I'm by no means an expert, I've never found a way to do it.
Brandon
A: 

Retrieve the default template of every control, with the XAML reader, then copy/paste and modify what you want... not very clean but I think this is the only way (I'm searching how to retrieve this default template)

Nicolas Dorier
A: 

In WPF, not sure about silverlight here a snippet of code to retrieve the template of Aero, you can try to copy/paste and change what you want:

        public Window1()
     {
      InitializeComponent();
      using(FileStream fs = new FileStream("C:/TextBoxTemplate.xaml", FileMode.Create))
      {
       var res = LoadThemeDictionary(typeof(TextBox), "Aero", "NormalColor");
       var buttonRes = res[typeof(TextBox)];
       XamlWriter.Save(buttonRes, fs);
      }
     }

     public static ResourceDictionary LoadThemeDictionary(Type t,
     string themeName, string colorScheme)
     {
      Assembly controlAssembly = t.Assembly;
      AssemblyName themeAssemblyName = controlAssembly.GetName();

      object[] attrs = controlAssembly.GetCustomAttributes(
        typeof(ThemeInfoAttribute), false);
      if(attrs.Length > 0)
      {
       ThemeInfoAttribute ti = (ThemeInfoAttribute)attrs[0];

       if(ti.ThemeDictionaryLocation ==
                  ResourceDictionaryLocation.None)
       {
        // There are no theme-specific resources.
        return null;
       }

       if(ti.ThemeDictionaryLocation ==
           ResourceDictionaryLocation.ExternalAssembly)
       {
        themeAssemblyName.Name += "." + themeName;
       }
      }

      string relativePackUriForResources = "/" +
        themeAssemblyName.FullName +
        ";component/themes/" +
        themeName + "." +
        colorScheme + ".xaml";

      Uri resourceLocater = new System.Uri(
        relativePackUriForResources, System.UriKind.Relative);

      return Application.LoadComponent(resourceLocater)
            as ResourceDictionary;
     }

I 've never used Silverlight, but I don't think there is a lot of things to do to adapt this template to Silverlight.

Source : Default template in WPF

Nicolas Dorier
+4  A: 

I've found a way to do this, by inheriting off the control and overriding the OnApplyTemplate. It's not ideal, but I think it's better than having to copy the entire control template. Here's an example of creating a borderless textbox, essentially disabling the mouse over visual state by always clearing the storyboard:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;

namespace SilverlightTestApplication
{
    public class BorderlessTextBox  : TextBox
    {
        public BorderlessTextBox()
        {
            BorderThickness = new System.Windows.Thickness(0);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            //Get the mouse over animation in the control template
            var MouseOverVisualState = GetTemplateChild("MouseOver") as VisualState;

            if (MouseOverVisualState == null)
                return;

            //get rid of the storyboard it uses, so the mouse over does nothing
            MouseOverVisualState.Storyboard = null;
        }
    }
}
mattmanser
A: 

Is this now possible in silverlight 3/4 ?

tony