Sunday, May 1, 2011

Can you override just part of a control template in silverlight

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>
From stackoverflow
  • 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.

    mattmanser : That's precisely what I'm trying to avoid having to do :) It just feels like a cut 'n paste disaster waiting to happen!
    Brandon : 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.
  • 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)

  • 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

  • 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;
            }
        }
    }
    
  • Is this now possible in silverlight 3/4 ?

0 comments:

Post a Comment