I have a Wpf FrameworkElement derived control that offers a custom AutomationPeer:
using System; using System.Collections.Generic; using System.Text; using System.Windows; using System.Windows.Automation.Peers; using System.Windows.Automation.Provider; namespace TSystem.Content { internal class MarkTopicElementAutomationPeer : FrameworkElementAutomationPeer, IValueProvider { private static readonly Dictionary<string, TcsMarkStates> StringToStateMap = new Dictionary<string, TcsMarkStates> { {"Positive", TcsMarkStates.Positive}, {"Negative", TcsMarkStates.Negative}, {"Neutral", TcsMarkStates.Neutral} }; #region Constructors public MarkTopicElementAutomationPeer(FrameworkElement owner) : base(owner) { if (!(owner is MarkTopicElement)) { throw new ArgumentException("Owner must derive from MarkTopicElement"); } } #endregion #region Automation Peer Overrides protected override string GetNameCore() { return "MarkElementAutomationPeer"; } protected override string GetAutomationIdCore() { StringBuilder id = new StringBuilder(); id.AppendFormat("MarkElement:{0}:{1}", OwnerAsElement.Caption, OwnerAsElement.ElementID); Topic parentTopic = OwnerAsElement.FindLogicalAncestorByType<Topic>(); if (null != parentTopic) { id.AppendFormat(":ParentTopic:{0}:{1}", parentTopic.GetType(), parentTopic.Instance); } return id.ToString(); } public override object GetPattern(PatternInterface patternInterface) { return patternInterface == PatternInterface.Value ? this : base.GetPattern(patternInterface); } protected override AutomationControlType GetAutomationControlTypeCore() { return AutomationControlType.Custom; } protected override bool IsContentElementCore() { return true; } protected override bool IsControlElementCore() { return true; } protected override bool IsEnabledCore() { return true; } #endregion #region IValueProvider Implementation public bool IsReadOnly { get { return OwnerAsElement.ReadOnly; } } public void SetValue(string value) { OwnerAsElement.ChangeMarkState(StateFromString(value)); } public string Value { get { return OwnerAsElement.MarkState.ToString(); } } #endregion #region Helper methods private MarkTopicElement OwnerAsElement { get { return (MarkTopicElement) Owner; } } private static TcsMarkStates StateFromString(string value) { TcsMarkStates state; return (StringToStateMap.TryGetValue(value, out state) ? state : TcsMarkStates.Neutral); } #endregion } }
However, when I try to access its SetValue implementation the ValuePattern:
WpfCustom mark = HistoryPage.EV.HistoryPage.Column1.Panel.StartedTopic.YesterdayMark; var markElement = (AutomationElement) mark.NativeElement; ValuePattern pattern = (ValuePattern) markElement.GetCurrentPattern(ValuePattern.Pattern); string currentValue = pattern.Current.Value; pattern.SetValue("Positive");
It throws this exception:
Result Message:
Test method EVTCSTest.HistoryStartedTest.SetStartedToPositive threw exception:
System.Windows.Automation.ElementNotAvailableException: Element not available ---> System.InvalidOperationException: Operation is not valid due to the current state of the object.
Result StackTrace:
at UIAutomationClient.IUIAutomationValuePattern.SetValue(String val)
at System.Windows.Automation.ValuePattern.SetValue(String value)
--- End of inner exception stack trace ---
at System.Windows.Automation.ValuePattern.SetValue(String value)
at EVTCSTest.HistoryStartedTest.SetStartedToPositive() in c:\Development\zTest\EVTCSTest\EVTCSTest\HistoryStartedTest.cs:line 46
Any ideas why this may be? I know that the element is enabled and is not read only.
I have confirmed that it is getting to my implementation of the read-only Value property of my automation peer. However it doesn't seem to even be reaching my implementation of SetValue.
Using recorded actions works just fine...but that is all mouse click, etc. based which is not what I want to do. If I do this, for example...
Mouse.Click(mark, new System.Drawing.Point(18, 9));
...instead of trying to access the value pattern and "directly" trying to set the value as shown in my earlier post, it works as expected. Are there any steps I am missing to be able to use ValuePattern.SetValue?
Thanks,
Kelly Hilliard