0

Problem

I needed to make controls that used images as backgrounds that could be any width without distorting the images. For example if I used a single image and stretched it the rounded corners of the image would become distorted.

Solution

The solution, given by Noxivs, was to use a custom UserControl with three images, two sides and a middle that is stretched.

Left Image Center Image Right Image

It is important to add SnapsToDevicePixels="True" to the UserControl Grid as without that a single pixel gap appeared between the images.

MainWindow.xaml

<Window x:Class="Testing.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ns="clr-namespace:Testing"
        Title="MainWindow" Height="350" Width="525">
    <Grid Name="MainGrid">
        <ns:ScalableTextBox TextBoxText="Added in XAML" Width="120" Margin="0,0,0,100">
        </ns:ScalableTextBox>
    </Grid>
</Window>

MainWindow.xaml.cs

ScalableTextBox scalableTextBox = new ScalableTextBox();
scalableTextBox.TextBoxText = "Added in C#";
scalableTextBox.Width = 100;
MainGrid.Children.Add(scalableTextBox);

ScalableTextBox.xaml.cs

public partial class ScalableTextBox : UserControl
{
    public ScalableTextBox()
    {
        InitializeComponent();
    }

    public string TextBoxText
    {
        get { return this.TextBoxName.Text; }
        set { this.TextBoxName.Text = value; }
    }
}

ScalableTextBox.xaml

<UserControl x:Class="Testing.ScalableTextBox"
         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="36" d:DesignWidth="50" Height="36" MinWidth="29">
    <Grid>
        <Grid SnapsToDevicePixels="True">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="14" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="14" />
            </Grid.ColumnDefinitions>
            <Image Grid.Column="0" Source="pack://siteoforigin:,,,/Images/left.png" />
            <Image Grid.Column="1" Stretch="Fill" Source="pack://siteoforigin:,,,/Images/center.png"/>
            <Image Grid.Column="2" Source="pack://siteoforigin:,,,/Images/right.png" />
        </Grid>
        <TextBox Name="TextBoxName" VerticalAlignment="Center"
                 HorizontalAlignment="Center" Background="{x:Null}"
                 BorderBrush="{x:Null}" FontSize="12"/>
    </Grid>
</UserControl>

Thanks again to Noxivs!

Falesh
  • 45
  • 5
  • Do you want the images given to be placed as a background to the textbox control? – Sangeetha Feb 08 '15 at 22:59
  • Yes. I create multiple controls in my C# code with varying width and want them all to use those two, or something similar, background images regardless of their width. – Falesh Feb 08 '15 at 23:28
  • This is not the easy way. I would choose to use `Path` geometry to define the border and the background and make the `Path` stretching to fill the entire `TextBox`. – kennyzx Feb 09 '15 at 05:03
  • I need to use images as some of the other controls will have more complex designs. I would also like to allow the possibility of users customizing the UI by changing the .png files to their own images. – Falesh Feb 09 '15 at 15:29

2 Answers2

0

I'm not sure to understand what you want but :

  • I think you can create exactly the same design of your images in XAML (vectorial keeps your style no matter the size).
  • What about the creation of your own control user with your textbox (0 opacity) and as many images as you want in the background ? (not really nice)

These are only suggestions.

EDIT :

And here is your scalable textbox :

I had to split your first image. https://i.stack.imgur.com/cGJ8u.png https://i.stack.imgur.com/Fo4Oo.png

<UserControl x:Class="YourNamespace.ScalableTextBox"
         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="300" d:DesignWidth="300" Height="36" MinWidth="29">
<Grid>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="14" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="14" />
        </Grid.ColumnDefinitions>
        <Image Grid.Column="0" Source="left.png" />
        <Image Grid.Column="1" Source="center.png" Stretch="Fill"/>
        <Image Grid.Column="2" Source="right.png" />
    </Grid>
    <TextBox VerticalAlignment="Center" Background="{x:Null}" BorderBrush="{x:Null}" FontSize="14" FontFamily="Comic Sans MS"  Margin="8,0"/>
</Grid>

<Window x:Class="YourNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ns="clr-namespace:_28400241"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <ns:ScalableTextBox></ns:ScalableTextBox>
    </Grid>
</Window>

I still think it is better to create the controls in XAML.

Regards.

EDIT 2 :

With a dynamic loading of images (myGrid is the main grid of the window, and i named the 3 images control in the ScalableTextBox object) :

    public MainWindow()
    {
        InitializeComponent();
        ScalableTextBox tb = new ScalableTextBox();
        tb.Width = 140;

        BitmapImage src = new BitmapImage();
        src.BeginInit();
        src.UriSource = new Uri("./left.png", UriKind.Relative);
        src.EndInit();

        tb.LeftImage.Source = src;

        src = new BitmapImage();
        src.BeginInit();
        src.UriSource = new Uri("./center.png", UriKind.Relative);
        src.EndInit();

        tb.CenterImage.Source = src;

        src = new BitmapImage();
        src.BeginInit();
        src.UriSource = new Uri("./right.png", UriKind.Relative);
        src.EndInit();

        tb.RightImage.Source = src;


        Grid.SetRow(tb, 0);
        Grid.SetColumn(tb, 0);
        myGrid.Children.Add(tb);
    }
  • This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post - you can always comment on your own posts, and once you have sufficient [reputation](http://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](http://stackoverflow.com/help/privileges/comment). – Dijkgraaf Feb 09 '15 at 00:36
  • With all respect, give a proper way to do what the user asks (in this context, create a scalable control) can be considered as an answer and not just as a comment ( that i'm not allowed to do for now). Reproduce the background image with vector technology (as we are able to do with WPF) is perfect for height and width resizing. – Quentin Baradat Feb 09 '15 at 01:15
  • That comment is the one automatically generated with you click certain review options. Your answer is more of a question about a question than an answer and hence was flagged as such. If you revise the answer and remove the uncertainties such as "I'm not sure" and "I think you can" and "What about .. ?" and give concrete examples then it could be considered an answer. As it stands now it doesn't fit the format of an answer in my opinion, and if enough other users agree it will be deleted. – Dijkgraaf Feb 09 '15 at 02:00
  • Thanks for your reply, that UserControl looks like the way forward. I have an issue that I haven't managed to work out though. The control works fine when added directly, i.e. "", however when I create it in the code, i.e. "ScalableTextBox scalableTextBox = new ScalableTextBox();, etc", it just comes up as text with no background and without the FontSize & FontFamily set. I have tried to work this out all day to no avail. – Falesh Feb 09 '15 at 21:10
  • Adding to that. I tried setting the image source in the C# as well, scalableTextBox.LeftImage.Source as well as setting a Loaded event to add a source but the images just don't get loaded. scalableTextBox.LeftImage.IsVisible returns false. If this is not a simple thing I will make a new post and update this one when I work that out. – Falesh Feb 09 '15 at 21:38
  • You can try this second edit, it works perfectly for me ( do not forget to copy images in the output folder :p ). – Quentin Baradat Feb 09 '15 at 22:45
  • I thought I must have been doing something daft as I couldn't find any reason why it was failing. Turns out I was, I set scalableTextBox.Content to the text I wanted to display. However what I should have done was named the TextBox and used: scalableTextBox.TextBoxName.Text. I'll update my main post with the full solution for posterity tomorrow. Thanks a lot for your help! – Falesh Feb 09 '15 at 23:45
0

I'm not sure to understand what you want but if you just want the image to appear as a background for the textbox, you could create a style for the textbox, modify the ControlTemplate and place a grid within it, containing the images.

For example (this is just to give you an idea of what I am trying to explain, not the exact code to implement):

<Style TargetType="{x:Type TextBox}">
  <Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="TextBox">
            <Grid>
                <Grid.ColumnDefinitions>
                   <ColumnDefinition Width="14" />
                   <ColumnDefinition Width="*" />
                   <ColumnDefinition Width="14" />
                </Grid.ColumnDefinitions>
                <Image Grid.Column="0" Source="left.png" />
                <Image Grid.Column="1" Source="center.png" Stretch="Fill"/>
                <Image Grid.Column="2" Source="right.png" />
                <ScrollViewer x:Name="ContentElement" Grid.Column="1"/>
            </Grid>
        </ControlTemplate>
    </Setter.Value>
</Setter>

Sangeetha
  • 485
  • 2
  • 9
  • 24