Bookmark and Share Share...    Subscribe to this feed Feed   About Christian Moser  


UI Automation with WPF

How to make TextBlock within a DataTemplate visible to UI Automation

WPF intentionally hides TextBlocks that are inside a DataTemplate to improve performance. To make them visible, you have to replace them by a Label which can be a performance hit, or you make a special UiAutomationTextBlock that overrides this behavior:

 
public class UiAutomationTextBlock : TextBlock
{
    protected override AutomationPeer OnCreateAutomationPeer()
    {
        return new ModifiedTextBlockAutomationPeer(this);
    }
 
    private class ModifiedTextBlockAutomationPeer : TextBlockAutomationPeer
    {
        public ModifiedTextBlockAutomationPeer(TextBlock textBlock)
            : base(textBlock)
        { }
 
        protected override bool IsControlElementCore()
        {
            return true;
        }
    }
}
 
 

The Idea for that solution was found here





Last modified: 2011-02-25 15:17:04
Copyright (c) by Christian Moser, 2011.

 Comments on this article

Show all comments
shaikjsdkalsd
Commented on 15.March 2011
dadasdasddasd
DSP
Commented on 28.June 2011
Great Work !!!
Sush
Commented on 5.August 2011
Boringgg!!!!
Shankar
Commented on 5.August 2011
It'S Working..An very usefull
venkatesh
Commented on 17.August 2011
I am trying to perform automation testing on my app which contains ribbon control.The ribbon buttons inside the ribbon control not getting detected.so i tried to implement Automationpeer for that control by the knowldge gained through this blog.But after implementing the automationpeer when i add the control to my app the controls are not getting displayed.Kindly help on this regard.please find the code below
public class UiAutomationRibbonButton : RibbonButton
{
static UiAutomationRibbonButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(UiAutomationRibbonButton), new FrameworkPropertyMetadata(typeof(UiAutomationRibbonButton)));
}

protected override AutomationPeer OnCreateAutomationPeer()
{
return new UiAutomationRibbonButtonAutomationPeer(this);
}
}

public class UiAutomationRibbonButtonAutomationPeer : RibbonButtonAutomationPeer ,IInvokeProvider
{
public UiAutomationRibbonButtonAutomationPeer(RibbonButton ribbonButton)
: base(ribbonButton)
{ }

protected override bool IsControlElementCore()
{
return true;
}

protected override string GetClassNameCore()
{
return "RibbonButton";
}

protected override string GetLocalizedControlTypeCore()
{
return "ribbonButton";
}

protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Button;
}

public override object GetPattern( PatternInterface patternInterface )
{
if( patternInterface == PatternInterface.Invoke )
{
return this;
}

return base.GetPattern( patternInterface );
}

private UiAutomationRibbonButton MyOwner
{
get
{
return (UiAutomationRibbonButton)base.Owner;
}
}

#region IInvokeProvider Members

public void Invoke()
{
RoutedEventArgs newEventArgs = new RoutedEventArgs(UiAutomationRibbonButton.ClickEvent);
MyOwner.RaiseEvent( newEventArgs );
}
#endregion

void IInvokeProvider.Invoke()
{
throw new NotImplementedException();
}
}

XAML Code :

<Window x:Class="WpfRibbonControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ribbon="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
xmlns:UIRibbon ="clr-namespace:WpfCustomControlLibrary1;assembly=WpfCustomControlLibrary1"
Title="MainWindow" Height="350" Width="525">


<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

<ribbon:Ribbon x:Name="Ribbon">
<ribbon:Ribbon.ApplicationMenu>
<ribbon:RibbonApplicationMenu SmallImageSource="Images\SmallIcon.png">
<ribbon:RibbonApplicationMenuItem Header="Hello _Ribbon"
x:Name="MenuItem1"
ImageSource="Images\LargeIcon.png"/>
</ribbon:RibbonApplicationMenu>
</ribbon:Ribbon.ApplicationMenu>
<ribbon:RibbonTab x:Name="HomeTab"
Header="Home">
<ribbon:RibbonGroup x:Name="Group1"
Header="Group1">

<UIRibbon:UiAutomationRibbonButton x:Name="Button1"
LargeImageSource="Images\LargeIcon.png"
Label="Button1" Click="Button1_Click" />

<UIRibbon:UiAutomationRibbonButton x:Name="Button2"
SmallImageSource="Images\SmallIcon.png"
Label="Button2" Click="Button2_Click" />

<UIRibbon:UiAutomationRibbonButton x:Name="Button3"
SmallImageSource="Images\SmallIcon.png"
Label="Button3" Click="Button3_Click" />

<UIRibbon:UiAutomationRibbonButton x:Name="Button4"
SmallImageSource="Images\SmallIcon.png"
Label="Button4" Click="Button4_Click" />

</ribbon:RibbonGroup>

</ribbon:RibbonTab>

</ribbon:Ribbon>


</Grid>


</Window>
venkatesh
Commented on 17.August 2011
I am trying to perform automation testing on my app which contains ribbon control.The ribbon buttons inside the ribbon control not getting detected.so i tried to implement Automationpeer for that control by the knowldge gained through this blog.But after implementing the automationpeer when i add the control to my app the controls are not getting displayed.Kindly help on this regard.please find the code below
public class UiAutomationRibbonButton : RibbonButton
{
static UiAutomationRibbonButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(UiAutomationRibbonButton), new FrameworkPropertyMetadata(typeof(UiAutomationRibbonButton)));
}

protected override AutomationPeer OnCreateAutomationPeer()
{
return new UiAutomationRibbonButtonAutomationPeer(this);
}
}

public class UiAutomationRibbonButtonAutomationPeer : RibbonButtonAutomationPeer ,IInvokeProvider
{
public UiAutomationRibbonButtonAutomationPeer(RibbonButton ribbonButton)
: base(ribbonButton)
{ }

protected override bool IsControlElementCore()
{
return true;
}

protected override string GetClassNameCore()
{
return "RibbonButton";
}

protected override string GetLocalizedControlTypeCore()
{
return "ribbonButton";
}

protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Button;
}

public override object GetPattern( PatternInterface patternInterface )
{
if( patternInterface == PatternInterface.Invoke )
{
return this;
}

return base.GetPattern( patternInterface );
}

private UiAutomationRibbonButton MyOwner
{
get
{
return (UiAutomationRibbonButton)base.Owner;
}
}

#region IInvokeProvider Members

public void Invoke()
{
RoutedEventArgs newEventArgs = new RoutedEventArgs(UiAutomationRibbonButton.ClickEvent);
MyOwner.RaiseEvent( newEventArgs );
}
#endregion

void IInvokeProvider.Invoke()
{
throw new NotImplementedException();
}
}

XAML Code :

<Window x:Class="WpfRibbonControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ribbon="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
xmlns:UIRibbon ="clr-namespace:WpfCustomControlLibrary1;assembly=WpfCustomControlLibrary1"
Title="MainWindow" Height="350" Width="525">


<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

<ribbon:Ribbon x:Name="Ribbon">
<ribbon:Ribbon.ApplicationMenu>
<ribbon:RibbonApplicationMenu SmallImageSource="Images\SmallIcon.png">
<ribbon:RibbonApplicationMenuItem Header="Hello _Ribbon"
x:Name="MenuItem1"
ImageSource="Images\LargeIcon.png"/>
</ribbon:RibbonApplicationMenu>
</ribbon:Ribbon.ApplicationMenu>
<ribbon:RibbonTab x:Name="HomeTab"
Header="Home">
<ribbon:RibbonGroup x:Name="Group1"
Header="Group1">

<UIRibbon:UiAutomationRibbonButton x:Name="Button1"
LargeImageSource="Images\LargeIcon.png"
Label="Button1" Click="Button1_Click" />

<UIRibbon:UiAutomationRibbonButton x:Name="Button2"
SmallImageSource="Images\SmallIcon.png"
Label="Button2" Click="Button2_Click" />

<UIRibbon:UiAutomationRibbonButton x:Name="Button3"
SmallImageSource="Images\SmallIcon.png"
Label="Button3" Click="Button3_Click" />

<UIRibbon:UiAutomationRibbonButton x:Name="Button4"
SmallImageSource="Images\SmallIcon.png"
Label="Button4" Click="Button4_Click" />

</ribbon:RibbonGroup>

</ribbon:RibbonTab>

</ribbon:Ribbon>


</Grid>


</Window>
daniel
Commented on 14.September 2011
Sounds good..............

Name
E-Mail (optional)
Comment