tags:

views:

667

answers:

3

I have a simple user control with a text box. I want to change the color of user control when the text box gets the focused This is what I have

<UserControl x:Class="OutLookContactList.ContactSearchControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="root" MinHeight="30" Loaded="UserControl_Loaded">

<UserControl.Resources>

    <Style x:Key="searchTextBoxStyle" TargetType="{x:Type TextBox}">
        <Style.Triggers>
            <Trigger Property="IsFocused" Value="true">
                <Setter TargetName="root" Property="Background" Value="{StaticResource OnMouseOverColor}" />
            </Trigger>
        </Style.Triggers>
    </Style>
</UserControl.Resources>

But I get the errot "TargetName property cannot be set on a style Setter". How can I Set the back ground color of user control when text box gets the focus? Thanks a bunch

A: 

If you were changing the background of the text box you need to remove the TargetName property:

<Style x:Key="searchTextBoxStyle" TargetType="{x:Type TextBox}">
    <Style.Triggers>
        <Trigger Property="IsFocused" Value="true">
            <Setter Property="Background" Value="{StaticResource OnMouseOverColor}" />
        </Trigger>
    </Style.Triggers>
</Style>

and change the TextBox that wants this style to be:

<TextBox Style="{StaticResource searchTextBoxStyle}" .... />

However, as you want to change the value of the parent user control this won't give you want you want.

You could certainly do it in the code behind by adding a GotFocus event handler and putting the code to change the background colour in there.

ChrisF
but this wouldn't set the back ground of the user control text box resides in. I want to change the color of user control when text box gets the focus.
Sheraz
Ah - I misunderstood.
ChrisF
changing in the code has extra maintainance as I would have to not only take care of setting the color when in focus, I'd have to bring the color back to normal when losing focus (twice as much work). That's why Trigger is best as it automatically resets the property when Setter value is not true anymore.
Sheraz
@Sheraz - no problem.
ChrisF
A: 

Here's some XAML that works in Kaxaml:

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;

  <Page.Style>
    <Style TargetType="Page">
      <Setter Property="Background" Value="#CCCCD0" />
      <Style.Triggers>
        <DataTrigger Binding="{Binding ElementName=txtSearch, Path=IsFocused}"
                     Value="true">
          <Setter Property="Background" Value="Black" />
        </DataTrigger>
      </Style.Triggers>
    </Style>
  </Page.Style>

  <TextBox x:Name="txtSearch" Width="100"
           HorizontalAlignment="Center" VerticalAlignment="Center" />

</Page>

You would change the Page object with your UserControl. I find it much easier to test these sorts of things out in a rapid prototyping tool such as Kaxaml before coding up the UserControl in VS.

Note that you have to set the default colour (in this case #CCCCD0) via a property setter and not via an attribute on the Page itself. This is because the attribute would override the value set by the trigger (because it's a style trigger), so even though the trigger would fire, it would always be trumpted by the local attribute specification, meaning that it wouldn't change. I only point this out because it's a fairly common gotcha.

Drew Noakes
this works fine in Kazaml but it's not working for IDE. Weird. Here is the exception that from output windowSystem.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=SearchTextBox'. BindingExpression:Path=IsFocused; DataItem=null; target element is 'ContactSearchControl' (Name='root'); target property is 'NoTarget' (type 'Object')clearly it's not able to find the SearchTextBox. If I take the xaml and paste in Kaxaml, it works fine. It seems like it has to do with the nested controls as I'm using that user control within another user control.
Sheraz
+1  A: 

Will it work to wrap the contents of your UserControl inside a Border object? If so, you can simply style the Border like so:

<UserControl x:Class="Sample2.ContactSearchControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="75" Width="300">
    <Border>
        <Border.Style>
            <Style TargetType="Border">
                <Setter Property="Background" Value="White" />
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsFocused, ElementName=txtSearch}" Value="true">
                        <Setter Property="Background" Value="Black" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Border.Style>
        <StackPanel>
            <TextBox x:Name="txtSearch" Text="Search" />
            <TextBox Text="Other" />
        </StackPanel>
    </Border>
</UserControl>

Update: (Answering Sheraz' Questions)

I'm not sure why ElementName doesn't work for accessing children within a UserControl. It might have something to do with the way the visual tree is constructed.

As for Trigger vs DataTrigger: Trigger is for dependency properties and DataTrigger is for databound properties (data or other controls). Since you are trying to style the Border, it makes more sense to place the DataTrigger there and have it watch the TextBox than to have the TextBox change the appearance of the Border.

As I understand it, the TargetName property of Setter is only applicable within a DataTemplate or ControlTemplate. (Info from Dr. WPF in this forum post)

Joseph Sturtevant
Yes it works. Thanks a lot Joseph.A few questions.Why didn't it work for UserControl and works for Border?Also how did you figure out that it's DataTrigger that needs to be used as my assumption was that DataTrigger is to work with data not the controls and I was keep on trying Trigger (instead of DataTrigger)
Sheraz
See my response in answer.
Joseph Sturtevant