Results 1 to 3 of 3

Thread: WPF Custom Control image binding

  1. #1

    Thread Starter
    New Member
    Join Date
    May 2011
    Posts
    11

    WPF Custom Control image binding

    Hello!

    I am trying to bind an image in a custom textbox control that I have created. The idea is to create a textbox which can have rounded corners, a custom watermark, and an icon at the left end, similar to the "magnifying glass" icon inside the "spotlight" search field textbox on a Mac. Here is the XAML for my default template at present:

    HTML Code:
    <Grid>
                            <Border CornerRadius="{TemplateBinding CornerRadius}" BorderBrush="{TemplateBinding BorderBrush}" 
                                    BorderThickness="{TemplateBinding BorderThickness}">
                                <Grid>
                                    <Border Name="opMask" CornerRadius="{TemplateBinding CornerRadius}" Background="Black"/>
                                    <Grid Background="{TemplateBinding Background}">
                                        <Grid.Resources>
                                            <BooleanToVisibilityConverter x:Key="BoolToVis"/>
                                        </Grid.Resources>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="Auto"/>
                                            <ColumnDefinition Width="*"/>
                                        </Grid.ColumnDefinitions>
                                        <Grid.OpacityMask>
                                            <VisualBrush Visual="{Binding ElementName=opMask}"/>
                                        </Grid.OpacityMask>
                                        <Image Grid.Column="0" Source="{TemplateBinding Icon}"/>
                                        <TextBlock Grid.Column="1" Background="Transparent" Text="{TemplateBinding Watermark}" FontStyle="Italic"
                                               Visibility="{Binding ElementName=userInput,Path=Text.IsEmpty,Converter={StaticResource BoolToVis}}"
                                               Foreground="{TemplateBinding WatermarkColor}" Margin="{TemplateBinding WatermarkMargin}"
                                               Opacity="{TemplateBinding WatermarkOpacity}"/>
                                        <TextBox Grid.Column="1"  x:Name="userInput" Text="{TemplateBinding Text}" Background="Transparent"
                                             BorderBrush="Transparent"/>
                                    </Grid>
                                </Grid>
                            </Border>
                        </Grid>
    I left out the <style> and <setter> tags for brevity, as I felt they are fairly self-explanatory. I can provide them if necessary. I also don't believe the code-behind is terribly important to post here, as all that is currently implemented is dependency properties, such as "Watermark", "WatermarkColor", etc. For reference, the "Icon" dependency property is of type String at the moment, but I have tried defining it as Image with no luck.

    I have also tried various versions of the following:

    HTML Code:
    <Image Grid.Column="0">
         <BitmapImage Source="{TemplateBinding Icon}"/>
    </Image>
    No cigar. What am I doing wrong here?

    Thanks so much for any help! (Btw, everything works great except for the image; I can successfully round off the ends of the textbox and add custom watermark text, color, and opacity.)

  2. #2

    Thread Starter
    New Member
    Join Date
    May 2011
    Posts
    11

    Re: WPF Custom Control image binding

    I found a solution on my own, though I am not certain it's the best in terms of performance. I wound up changing the type of the Icon dependency property back to Image and defined the following in the XAML:

    HTML Code:
    <Image Stretch="None" Margin="{TemplateBinding IconMargin}"
         Source="{Binding RelativeSource={RelativeSource FindAncestory, AncestoryType={x:Type TextBox}}, Path=Icon.Source}"/>
    Works very well, but I believe this is instantiating two separate images for each textbox control. One or the Icon property and another for the Image tag in the XAML.

    Any ideas?

    Here's the current state of the ControlTemplate (I've made some aesthetic improvements as well):

    HTML Code:
    <Grid>
         <Border x:Name="opMask" CornerRadius="{TemplateBinding CornerRadius}" Background="White" BorderThickness="0"/>
         <Grid Background="{TemplateBinding Background}">
              <Grid.Resources>
                   <BooleanToVisibilityConverter x:Key="BoolToVis"/>
              </Grid.Resources>
              <Grid.ColumnDefinitions>
                   <ColumnDefinition Width="Auto"/>
                   <ColumnDefinition Width="*"/>
              </Grid.ColumnDefinitions>
              <Grid.OpacityMask>
                   <VisualBrush Visual="{Binding ElementName=opMask}"/>
              </Grid.OpacityMask>
              <Image Grid.Column="0" Stretch="None" Margin="{TemplateBinding IconMargin}"
                                       Source="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}, Path=Icon.Source}"/>
              <TextBlock Grid.Column="1" Background="Transparent" Text="{TemplateBinding Watermark}" FontStyle="Italic"
                                               Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TextBox}}, Path=Text.IsEmpty, Converter={StaticResource BoolToVis}}"
                                               Foreground="{TemplateBinding WatermarkColor}" Margin="{TemplateBinding WatermarkMargin}"
                                               Opacity="{TemplateBinding WatermarkOpacity}" FontWeight="Normal"/>
              <ScrollViewer Grid.Column="1" x:Name="PART_ContentHost" Background="Transparent" 
                                              VerticalScrollBarVisibility="{TemplateBinding VerticalScrollBarVisibility}"
                                              Margin="{TemplateBinding TextMargin}"/>
          </Grid>
          <Border BorderBrush="Black" BorderThickness="1,1,0,0" Margin="0,0,0,0" CornerRadius="{TemplateBinding CornerRadius}" Height="{TemplateBinding ActualHeight}"
                                            Width="{TemplateBinding ActualWidth}" Background="Transparent">
               <Border.Effect>
                    <BlurEffect Radius="3"/>
               </Border.Effect>
               <Border.OpacityMask>
                    <VisualBrush Visual="{Binding ElementName=opMask}"/>
               </Border.OpacityMask>
          </Border>
          <Border CornerRadius="{TemplateBinding CornerRadius}" BorderBrush="{TemplateBinding BorderBrush}"
                                                BorderThickness="{TemplateBinding BorderThickness}" Background="Transparent"/>
    </Grid>

  3. #3

    Thread Starter
    New Member
    Join Date
    May 2011
    Posts
    11

    Re: WPF Custom Control image binding

    Okay, I got it. This is a much much better solution. I simply added a ContentPresenter to the "Auto" sized Grid column to the left of the Scrollviewer, so that any content can be added (including images) and did away with the "Icon" dependency property. Then, for kicks, I added one to the right as well, so that content could be added at the right end (maybe an "X" icon for delete?). In the spirit of this new discovery, I also converted the Watermark to a ContentPresenter, so that any type of content could be used as a watermark. The (semi) final XAML will follow. The only thing on my list left to do to this control is to figure out Autocompletion and it will be final.

    HTML Code:
    <!--Extended Textbox-->
        <Style TargetType="{x:Type local:ExTextBox}">
            <Style.Resources>
                <local:HalfValueConverter x:Key="HalveDbl"/>
            </Style.Resources>
            <Setter Property="Height" Value="26"/>
            <Setter Property="CornerRadius" Value="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self},Converter={StaticResource HalveDbl}}"/>
            <Setter Property="Background" Value="GhostWhite"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Setter Property="TextMargin" Value="10,6,6,0"/>
            <Setter Property="SnapsToDevicePixels" Value="True"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:ExTextBox}">
                        <Grid>
                            <Border x:Name="opMask" CornerRadius="{TemplateBinding CornerRadius}" Background="White" BorderThickness="0"/>
                            <Border BorderBrush="Black" BorderThickness="1,1,0,0" Margin="0" CornerRadius="{TemplateBinding CornerRadius}" Height="{TemplateBinding ActualHeight}"
                                            Width="{TemplateBinding ActualWidth}" Background="{TemplateBinding Background}">
                                <Border.Effect>
                                    <BlurEffect Radius="3"/>
                                </Border.Effect>
                                <Border.OpacityMask>
                                    <VisualBrush Visual="{Binding ElementName=opMask}"/>
                                </Border.OpacityMask>
                            </Border>
                            <Border CornerRadius="{TemplateBinding CornerRadius}" BorderBrush="{TemplateBinding BorderBrush}"
                                                BorderThickness="{TemplateBinding BorderThickness}" Background="Transparent"/>
                            <Grid Background="Transparent">
                                <Grid.Resources>
                                    <BooleanToVisibilityConverter x:Key="BoolToVis"/>
                                </Grid.Resources>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="Auto"/>
                                </Grid.ColumnDefinitions>
                                <Grid.OpacityMask>
                                    <VisualBrush Visual="{Binding ElementName=opMask}"/>
                                </Grid.OpacityMask>
                                <ContentPresenter Grid.Column="0" Content="{TemplateBinding LeftContent}"/>
                                <ContentPresenter Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TextBox}}, Path=Text.IsEmpty, Converter={StaticResource BoolToVis}}"
                                                  Grid.Column="1" Content="{TemplateBinding Watermark}" />
                                <ScrollViewer Grid.Column="1" x:Name="PART_ContentHost" Background="Transparent" 
                                              VerticalScrollBarVisibility="{TemplateBinding VerticalScrollBarVisibility}"
                                              Margin="{TemplateBinding TextMargin}" Cursor="IBeam" />
                                <ContentPresenter Grid.Column="2" Content="{TemplateBinding RightContent}"/>
                            </Grid>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width