Working with UI Element Repository
The Repository is Ranorex's powerful system for organizing and managing UI elements in your automation projects. This guide will teach you how to effectively use repositories programmatically through the API.
What is a Repository?
A Repository in Ranorex is a structured collection of UI elements that provides:
- Centralized element management: All UI elements in one place
- Maintainable element paths: Easy to update when UI changes
- IntelliSense support: Type-safe access to elements
- Hierarchical organization: Logical grouping of related elements
Repository Structure
Basic Repository Layout
MyAppRepository
├── MainWindow
│ ├── MenuBar
│ │ ├── FileMenu
│ │ └── EditMenu
│ ├── ToolBar
│ │ ├── SaveButton
│ │ └── OpenButton
│ └── StatusBar
└── LoginDialog
├── UsernameField
├── PasswordField
└── LoginButton
Generated Repository Code
When you create a repository in Ranorex Studio, it generates code like this:
public partial class MyAppRepository
{
private static MyAppRepository _instance;
public static MyAppRepository Instance
{
get
{
if (_instance == null)
_instance = new MyAppRepository();
return _instance;
}
}
// Element containers
public MyAppRepositoryFolders.MainWindowAppFolder MainWindow { get; private set; }
public MyAppRepositoryFolders.LoginDialogAppFolder LoginDialog { get; private set; }
private MyAppRepository()
{
MainWindow = new MyAppRepositoryFolders.MainWindowAppFolder(this);
LoginDialog = new MyAppRepositoryFolders.LoginDialogAppFolder(this);
}
}
Using Repository Elements
Basic Element Access
using Ranorex;
using Ranorex.Core;
class RepositoryExample
{
static void Main(string[] args)
{
Host.Initialize();
try
{
// Get repository instance
var repo = MyAppRepository.Instance;
// Access elements through repository
repo.LoginDialog.UsernameField.Click();
repo.LoginDialog.UsernameField.PressKeys("john.doe");
repo.LoginDialog.PasswordField.Click();
repo.LoginDialog.PasswordField.PressKeys("password123");
repo.LoginDialog.LoginButton.Click();
// Wait for main window to appear
repo.MainWindow.Self.WaitForExists(10000);
// Interact with main window elements
repo.MainWindow.MenuBar.FileMenu.Click();
repo.MainWindow.ToolBar.SaveButton.Click();
Console.WriteLine("Repository automation completed successfully!");
}
finally
{
Host.Shutdown();
}
}
}
Element Properties and Methods
var repo = MyAppRepository.Instance;
var button = repo.MainWindow.ToolBar.SaveButton;
// Check element state
if (button.Exists)
{
Console.WriteLine($"Button is enabled: {button.Enabled}");
Console.WriteLine($"Button is visible: {button.Visible}");
Console.WriteLine($"Button text: {button.Text}");
}
// Element interactions
button.Click(); // Click the button
button.DoubleClick(); // Double-click
button.MoveTo(); // Move mouse to element
button.PressKeys("Enter"); // Send keys
button.Highlight(); // Highlight element
// Get element information
var location = button.Location; // Screen coordinates
var size = button.Size; // Element size
var screenshot = button.CaptureCompressedImage(); // Take screenshot
Advanced Repository Techniques
Repository Folders and Organization
// Repository folders help organize related elements
public class MyAppRepositoryFolders
{
public class MainWindowAppFolder
{
private readonly MyAppRepository _repo;
public MainWindowAppFolder(MyAppRepository repo)
{
_repo = repo;
Self = repo.Self.FindSingle<Form>("/form[@title='MyApp']");
MenuBar = new MenuBarAppFolder(_repo);
ToolBar = new ToolBarAppFolder(_repo);
}
public Form Self { get; private set; }
public MenuBarAppFolder MenuBar { get; private set; }
public ToolBarAppFolder ToolBar { get; private set; }
}
public class MenuBarAppFolder
{
private readonly MyAppRepository _repo;
public MenuBarAppFolder(MyAppRepository repo)
{
_repo = repo;
FileMenu = repo.Self.FindSingle<MenuItem>("/form[@title='MyApp']/menubar/menuitem[@text='File']");
EditMenu = repo.Self.FindSingle<MenuItem>("/form[@title='MyApp']/menubar/menuitem[@text='Edit']");
}
public MenuItem FileMenu { get; private set; }
public MenuItem EditMenu { get; private set; }
}
}
Dynamic Repository Elements
public partial class MyAppRepository
{
// Dynamic element access with parameters
public Button GetToolbarButton(string buttonText)
{
var path = $"/form[@title='MyApp']/toolbar/button[@text='{buttonText}']";
return Self.FindSingle<Button>(path);
}
public ListItem GetListItem(int index)
{
var path = $"/form[@title='MyApp']/list/listitem[@index='{index}']";
return Self.FindSingle<ListItem>(path);
}
public Text GetTextFieldByName(string fieldName)
{
var path = $"//text[@name='{fieldName}']";
return Self.FindSingle<Text>(path);
}
}
// Usage
var repo = MyAppRepository.Instance;
var dynamicButton = repo.GetToolbarButton("Save");
var firstItem = repo.GetListItem(0);
var customField = repo.GetTextFieldByName("customerName");
Repository with Data Binding
public class LoginData
{
public string Username { get; set; }
public string Password { get; set; }
}
public partial class MyAppRepository
{
public void PerformLogin(LoginData loginData)
{
LoginDialog.UsernameField.Click();
LoginDialog.UsernameField.PressKeys(loginData.Username);
LoginDialog.PasswordField.Click();
LoginDialog.PasswordField.PressKeys(loginData.Password);
LoginDialog.LoginButton.Click();
}
public void FillForm(Dictionary<string, string> formData)
{
foreach (var kvp in formData)
{
var field = GetTextFieldByName(kvp.Key);
field.Click();
field.PressKeys("{Ctrl}a"); // Select all
field.PressKeys(kvp.Value);
}
}
}
// Usage
var loginData = new LoginData
{
Username = "john.doe",
Password = "secure123"
};
repo.PerformLogin(loginData);
var formData = new Dictionary<string, string>
{
["firstName"] = "John",
["lastName"] = "Doe",
["email"] = "john.doe@example.com"
};
repo.FillForm(formData);
Creating Repository Programmatically
Manual Repository Creation
using Ranorex.Core.Repository;
public class ProgrammaticRepository
{
private readonly RepositoryHost _host;
public ProgrammaticRepository()
{
_host = new RepositoryHost();
InitializeElements();
}
private void InitializeElements()
{
// Define element paths
var mainWindowPath = "/form[@title='MyApp']";
var loginDialogPath = "/form[@title='Login']";
// Create repository items
var mainWindow = new RepositoryItem("MainWindow", mainWindowPath, typeof(Form));
var loginDialog = new RepositoryItem("LoginDialog", loginDialogPath, typeof(Form));
// Add to repository
_host.AddItem(mainWindow);
_host.AddItem(loginDialog);
// Create child elements
var usernameField = new RepositoryItem("UsernameField",
loginDialogPath + "/text[@name='username']", typeof(Text));
var passwordField = new RepositoryItem("PasswordField",
loginDialogPath + "/text[@name='password']", typeof(Text));
loginDialog.AddChild(usernameField);
loginDialog.AddChild(passwordField);
}
// Element access methods
public Form GetMainWindow()
{
return _host.FindSingle<Form>("MainWindow");
}
public Form GetLoginDialog()
{
return _host.FindSingle<Form>("LoginDialog");
}
public Text GetUsernameField()
{
return _host.FindSingle<Text>("LoginDialog.UsernameField");
}
}
Repository with Configuration
public class ConfigurableRepository
{
private readonly Dictionary<string, string> _elementPaths;
public ConfigurableRepository(string configFile = null)
{
_elementPaths = LoadConfiguration(configFile);
}
private Dictionary<string, string> LoadConfiguration(string configFile)
{
// Load from file, database, or use defaults
var config = new Dictionary<string, string>();
if (configFile != null && File.Exists(configFile))
{
var json = File.ReadAllText(configFile);
config = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
}
else
{
// Default configuration
config = new Dictionary<string, string>
{
["MainWindow"] = "/form[@title='MyApp']",
["LoginDialog"] = "/form[@title='Login']",
["UsernameField"] = "/form[@title='Login']/text[@name='username']",
["PasswordField"] = "/form[@title='Login']/text[@name='password']",
["LoginButton"] = "/form[@title='Login']/button[@text='Login']"
};
}
return config;
}
public T GetElement<T>(string elementName) where T : Element
{
if (_elementPaths.TryGetValue(elementName, out string path))
{
return Host.Local.FindSingle<T>(path);
}
throw new InvalidOperationException($"Element '{elementName}' not found in configuration");
}
public void UpdateElementPath(string elementName, string newPath)
{
_elementPaths[elementName] = newPath;
}
}
// Usage
var repo = new ConfigurableRepository("elements.json");
var mainWindow = repo.GetElement<Form>("MainWindow");
var loginButton = repo.GetElement<Button>("LoginButton");
// Update paths at runtime
repo.UpdateElementPath("LoginButton", "/form[@title='New Login']/button[@text='Sign In']");
Repository Best Practices
1. Logical Organization
// Group related elements in folders
MyAppRepository
├── Authentication
│ ├── LoginDialog
│ └── RegistrationForm
├── MainInterface
│ ├── Navigation
│ ├── ContentArea
│ └── StatusBar
└── Settings
├── UserPreferences
└── SystemConfiguration
2. Descriptive Naming
// Good naming conventions
repo.UserManagement.CreateUserDialog.FirstNameField
repo.UserManagement.CreateUserDialog.LastNameField
repo.UserManagement.CreateUserDialog.EmailField
repo.UserManagement.CreateUserDialog.SaveButton
// Avoid generic names
repo.Dialog1.Text1
repo.Dialog1.Text2
repo.Dialog1.Button1
3. Error Handling
public class SafeRepository
{
private readonly MyAppRepository _repo;
public SafeRepository()
{
_repo = MyAppRepository.Instance;
}
public bool TryClickButton(Func<Button> buttonSelector, out string error)
{
error = null;
try
{
var button = buttonSelector();
if (button.Exists && button.Enabled)
{
button.Click();
return true;
}
error = "Button not available for clicking";
return false;
}
catch (Exception ex)
{
error = $"Error clicking button: {ex.Message}";
return false;
}
}
}
// Usage
var safeRepo = new SafeRepository();
if (safeRepo.TryClickButton(() => repo.MainWindow.SaveButton, out string error))
{
Console.WriteLine("Button clicked successfully");
}
else
{
Console.WriteLine($"Failed to click button: {error}");
}
4. Repository Validation
public static class RepositoryValidator
{
public static void ValidateRepository(MyAppRepository repo)
{
var validationResults = new List<string>();
// Check if main containers exist
if (!repo.MainWindow.Self.Exists)
validationResults.Add("Main window not found");
if (!repo.LoginDialog.Self.Exists)
validationResults.Add("Login dialog not found");
// Check critical elements
var criticalElements = new Dictionary<string, Func<Element>>
{
["Username Field"] = () => repo.LoginDialog.UsernameField,
["Password Field"] = () => repo.LoginDialog.PasswordField,
["Login Button"] = () => repo.LoginDialog.LoginButton
};
foreach (var kvp in criticalElements)
{
try
{
var element = kvp.Value();
if (!element.Exists)
validationResults.Add($"{kvp.Key} not found");
}
catch (Exception ex)
{
validationResults.Add($"{kvp.Key} validation failed: {ex.Message}");
}
}
if (validationResults.Any())
{
var errorMessage = "Repository validation failed:\n" +
string.Join("\n", validationResults);
throw new InvalidOperationException(errorMessage);
}
}
}
// Validate before using repository
try
{
RepositoryValidator.ValidateRepository(MyAppRepository.Instance);
// Proceed with automation
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"Repository validation failed: {ex.Message}");
Environment.Exit(1);
}
Integration with Test Frameworks
Repository with Page Object Pattern
public abstract class BasePage
{
protected readonly MyAppRepository Repository;
protected BasePage()
{
Repository = MyAppRepository.Instance;
}
public abstract bool IsLoaded();
public abstract void WaitForLoad(TimeSpan timeout);
}
public class LoginPage : BasePage
{
public override bool IsLoaded()
{
return Repository.LoginDialog.Self.Exists;
}
public override void WaitForLoad(TimeSpan timeout)
{
Repository.LoginDialog.Self.WaitForExists(timeout);
}
public void Login(string username, string password)
{
WaitForLoad(TimeSpan.FromSeconds(10));
Repository.LoginDialog.UsernameField.Click();
Repository.LoginDialog.UsernameField.PressKeys(username);
Repository.LoginDialog.PasswordField.Click();
Repository.LoginDialog.PasswordField.PressKeys(password);
Repository.LoginDialog.LoginButton.Click();
}
public bool IsLoginSuccessful()
{
return Repository.MainWindow.Self.Exists;
}
}
public class MainPage : BasePage
{
public override bool IsLoaded()
{
return Repository.MainWindow.Self.Exists;
}
public override void WaitForLoad(TimeSpan timeout)
{
Repository.MainWindow.Self.WaitForExists(timeout);
}
public void SaveDocument()
{
Repository.MainWindow.ToolBar.SaveButton.Click();
}
}
Next Steps
Now that you understand repository management:
- Advanced UI Interaction - Learn complex interaction patterns
- Custom Validation Logic - Build robust validations
- Examples - See practical repository usage
Performance Considerations
- Lazy loading: Repository elements are typically loaded on first access
- Caching: Avoid repeatedly finding the same elements
- Scope management: Use appropriate timeouts and search scopes
- Memory management: Dispose of repository instances when appropriate
For advanced repository patterns and techniques, explore our comprehensive guides and practical examples.