2017-02-21 108 views
0

Я использую среду TestStack White для автоматизации тестирования приложения WPF Необходимо открыть модальное окно и получить доступ к TextBox. Все работает хорошо, но белые не могут найти Textbox, хотя он находит другие элементы окнаTestStack White не находит TextBox в приложении WPF

Я попытался следующие строки кода:

TestStack.White.UIItems.TextBox TextBox = CreateBranch.Get<TestStack.White.UIItems.TextBox>(SearchCriteria.byAutomationId("Title")); 

где CreateBranch модальное окно

Я также пробовал (SearchCriteria.All), (SearchCriteria.ByControlType) и ничего не работает

инструмент

Coded UI находит этот элемент хорошо AutomationID, но мне нужно сделать это в Белой

UISpy и другие аналогичные инструменты признают этот контроль и увидеть его AutomationID

Это текстовое поле в пользовательский элемент управления, вот код для этого, я изменил имя пространства имен для обеспечения конфиденциальности:

using System; 
using System.ComponentModel; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Input; 
using System.Windows.Interactivity; 
using System.Windows.Media; 

namespace Test.Wpf.Controls.XTextBox 
{ 
    [TemplatePart(Name = "PART_Watermark", Type = typeof(TextBlock))] 
    [TemplatePart(Name = "PART_Pasword", Type = typeof(TextBlock))] 
    public class XTextBox : TextBox 
    { 
     #region Static 
     static XTextBox() 
     { 
      DefaultStyleKeyProperty.OverrideMetadata(typeof(XTextBox), new FrameworkPropertyMetadata(typeof(XTextBox))); 
     } 
     #endregion //Static 

     #region Fields 

     private TextBlock PART_Watermark; 
     private TextBlock PART_Pasword; 

     #endregion //Fields 

     #region DependencyProperties 

     public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register(
      "Watermark", 
      typeof(String), 
      typeof(XTextBox), 
      new PropertyMetadata(String.Empty)); 

     public static readonly DependencyProperty WatermarkVerticalAlignmentProperty = DependencyProperty.Register(
      "WatermarkVerticalAlignment", 
      typeof(VerticalAlignment), 
      typeof(XTextBox), 
      new PropertyMetadata(VerticalAlignment.Stretch)); 

     public static readonly DependencyProperty WatermarkForegroundProperty = DependencyProperty.Register(
      "WatermarkForeground", 
      typeof(Brush), 
      typeof(XTextBox), 
      new PropertyMetadata(new SolidColorBrush(Colors.Black))); 

     public static readonly DependencyProperty WatermarkFontSizeProperty = DependencyProperty.Register(
      "WatermarkFontSize", 
      typeof(Double), 
      typeof(XTextBox), 
      new PropertyMetadata(12.0)); 

     public static readonly DependencyProperty IsFloatingProperty = DependencyProperty.Register(
      "IsFloating", 
      typeof(Boolean), 
      typeof(XTextBox), 
      new PropertyMetadata(false)); 

     public static readonly DependencyProperty IsAccessNegativeProperty = DependencyProperty.Register(
      "IsAccessNegative", 
      typeof(Boolean), 
      typeof(XTextBox), 
      new PropertyMetadata(true)); 

     public static readonly DependencyProperty IsDigitOnlyProperty = DependencyProperty.Register(
      "IsDigitOnly", 
      typeof(Boolean), 
      typeof(XTextBox), 
      new PropertyMetadata(false)); 

     public static readonly DependencyProperty MaxValueProperty = DependencyProperty.Register(
      "MaxValue", 
      typeof(Single), 
      typeof(XTextBox), 
      new PropertyMetadata(Single.NaN)); 

     public static readonly DependencyProperty IsPasswordProperty = DependencyProperty.Register(
      "IsPassword", 
      typeof(Boolean), 
      typeof(XTextBox), 
      new PropertyMetadata(false)); 

     public static readonly DependencyProperty VisibilityMainTextProperty = DependencyProperty.Register(
      "VisibilityMainText", 
      typeof(Visibility), 
      typeof(XTextBox), 
      new PropertyMetadata(Visibility.Visible)); 

     #endregion //DependencyProperties 

     #region Properties 
     [Description("Gets or sets the watermark title")] 
     public String Watermark 
     { 
      get { return (String)GetValue(WatermarkProperty); } 
      set { SetValue(WatermarkProperty, value); } 
     } 

     [Description("Gets or sets the watermark vertical alignment")] 
     public VerticalAlignment WatermarkVerticalAlignment 
     { 
      get { return (VerticalAlignment)GetValue(WatermarkVerticalAlignmentProperty); } 
      set { SetValue(WatermarkVerticalAlignmentProperty, value); } 
     } 


     [Description("Gets or sets the watermark title color")] 
     public Brush WatermarkForeground 
     { 
      get { return (Brush)GetValue(WatermarkVerticalAlignmentProperty); } 
      set { SetValue(WatermarkVerticalAlignmentProperty, value); } 
     } 

     [Description("Gets or sets the watermark title font size")] 
     public Double WatermarkFontSize 
     { 
      get { return (Double)GetValue(WatermarkVerticalAlignmentProperty); } 
      set { SetValue(WatermarkVerticalAlignmentProperty, value); } 
     } 

     [Description("Gets or sets the textbox floating mode")] 
     public Boolean IsFloating 
     { 
      get { return (Boolean)GetValue(IsFloatingProperty); } 
      set { SetValue(IsFloatingProperty, value); } 
     } 

     [Description("Gets or sets the textbox access of negative values")] 
     public Boolean IsAccessNegative 
     { 
      get { return (Boolean)GetValue(IsAccessNegativeProperty); } 
      set { SetValue(IsAccessNegativeProperty, value); } 
     } 

     [Description("Gets or sets the textbox chars type")] 
     public Boolean IsDigitOnly 
     { 
      get { return (Boolean)GetValue(IsDigitOnlyProperty); } 
      set { SetValue(IsDigitOnlyProperty, value); } 
     } 

     [Description("Gets or sets the max input value (enable in digit mode only)")] 
     public Single MaxValue 
     { 
      get { return (Single)GetValue(MaxValueProperty); } 
      set { SetValue(MaxValueProperty, value); } 
     } 

     [Description("Gets or sets the textbox is passwordbox")] 
     public Boolean IsPassword 
     { 
      get { return (Boolean)GetValue(IsPasswordProperty); } 
      set { SetValue(IsPasswordProperty, value); } 
     } 

     public Visibility VisibilityMainText 
     { 
      get { return (Visibility)GetValue(VisibilityMainTextProperty); } 
      set { SetValue(VisibilityMainTextProperty, value); } 
     } 

     #endregion //Properties 

     public override void OnApplyTemplate() 
     { 
      base.OnApplyTemplate(); 
      PART_Watermark = GetTemplateChild("PART_Watermark") as TextBlock; 
      PART_Pasword = GetTemplateChild("PART_Pasword") as TextBlock; 
      SetWatermarkVisibility(); 
      if (IsPassword) 
      { 
       VisibilityMainText = Visibility.Collapsed; 
       if (PART_Pasword != null) 
       { 
        PART_Pasword.Visibility = Visibility.Visible; 
        PART_Pasword.FontSize = 20; 
       } 
      } 
      else 
      { 
       VisibilityMainText = Visibility.Visible; 
      } 

      DataObject.AddPastingHandler(this, OnPaste); 
     } 

     protected void OnPaste(Object sender, DataObjectPastingEventArgs e) 
     { 
      try 
      { 
       var isText = e.SourceDataObject.GetDataPresent(DataFormats.UnicodeText, true); 
       if (!isText) return; 
       var text = e.SourceDataObject.GetData(DataFormats.UnicodeText) as String; 
       if (!String.IsNullOrEmpty(text)) 
       { 
        if (IsDigitOnly) 
        { 
         if (!IsAccessNegative) 
         { 
          var ch = text[0]; 
          if (ch == 45) 
          { 
           e.CancelCommand(); 
          } 
         } 
         for (int i = 0; i < text.Length; i++) 
         { 
          if (i == 0) 
          { 
           if (IsAccessNegative && text[i] == 45) 
           { 
            continue; 
           } 
          } 
          if (!Char.IsDigit(text[0])) 
           e.CancelCommand(); 
         } 
        } 
       } 
      } 
      catch (Exception) 
      { 
       // ignored 
       e.Handled = true; 
      } 
     } 

     protected override void OnTextChanged(TextChangedEventArgs e) 
     { 
      base.OnTextChanged(e); 
      SetWatermarkVisibility(); 
      if (IsPassword) 
      { 
       PART_Pasword.Text = new String('•', Text.Length); 
      } 
     } 

     protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e) 
     { 
      base.OnLostKeyboardFocus(e); 
      SetWatermarkVisibility(); 
     } 

     protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e) 
     { 
      base.OnGotKeyboardFocus(e); 
      if (PART_Watermark != null) 
      { 
       PART_Watermark.Visibility = Visibility.Hidden; 
      } 
     } 

     protected override void OnPreviewTextInput(TextCompositionEventArgs e) 
     { 
      base.OnPreviewTextInput(e); 
      if (e.Text.Length == 0) 
      { 
       e.Handled = true; 
       return; 
      } 
      if (IsDigitOnly) 
      { 
       var ch = e.Text[0]; 
       if (!Char.IsDigit(ch) && ch != 8 && ch != 46) 
       { 
        if (!(IsAccessNegative && ch == 45)) 
         e.Handled = true; 
       } 
       if (IsFloating) 
       { 
        if (ch == 46 && Text.IndexOf('.') != -1) 
        { 
         e.Handled = true; 
         return; 
        } 
       } 

       if (!IsAccessNegative) 
       { 
        if (ch == 45) 
        { 
         e.Handled = true; 
        } 
       } 
      } 
     } 

     #region Private 

     private void SetWatermarkVisibility() 
     { 
      if (PART_Watermark != null) 
      { 
       PART_Watermark.Visibility = (Text != String.Empty || IsKeyboardFocused)? Visibility.Hidden : Visibility.Visible; 
      } 
     } 
     #endregion 
    } 
} 

Screenshot from UISpy

+0

Не могли бы вы опубликовать код для поиска окна, а также снимок экрана вывода UISpys для текстовое поле? Обычно я обнаруживаю, что, когда я не могу найти элемент управления в окне, я случайно нашел другое окно. Как правило, окна в конечном итоге являются подсказками или чем-то похожими. –

+0

application = TestStack.White.Application.Launch (ApplicationPath); TestStack.White.UIItems.WindowItems.Window mainWindow = application.GetWindow (SearchCriteria.ByText ("title"), TestStack.White.Factory.InitializeOption.NoCache); // затем делать действия для открытия модального окна и при его открытии TestStack.White.UIItems.WindowItems.Window CreateBranch = mainWindow.ModalWindow (SearchCriteria.All); Добавлен снимок экрана. В Edit есть две полосы прокрутки, но они не используются. Когда я пытался использовать рекомендации DLDR с добавлением AutomationPeer, управление распознается как «Пользовательский», а не «Редактировать» –

ответ

0

Позвольте мне знать, если это работает

TextBox = (TextBox)CreateBranch 
     .Get(SearchCriteria.ByAutomationId("Title").AndOfFramework(WindowsFramework.Wpf)); 

Ed ITED после нового источник добавил

Вы должны создать специальную AutomationPeer для пользовательского элемента управления и вернуть его с помощью переопределения метода OnCreateAutomationPeer().

Ваш элемент управления является подклассом элемента управления TextBox, поэтому вы можете просто вернуть новый экземпляр TextBoxAutomationPeer или создать из него свой собственный AutomationPeer.

public class XTextBox : TextBox 
{ 
... 
    protected override AutomationPeer OnCreateAutomationPeer() 
    { 
     return new XTextBoxAutomationPeer(this); 
     // or just use the TextBoxAutomationPeer 
     // return new TextBoxAutomationPeer(this); 
    } 
... 
} 

Обычай автоматизации экспертной

public class XTextBoxAutomationPeer : TextBoxAutomationPeer 
{ 
    public XTextBoxAutomationPeer(XTextBox owner) 
     : base(owner) 
    { 
    } 

    protected override string GetClassNameCore() 
    { 
     return "XTextBox"; 
    } 
} 
+0

Нет, это не работает –

+0

Является ли ваш текстовый блок настраиваемым? Не могли бы вы предоставить код XAML? – DLDR

+0

Вот XAML код: И есть XTextBox. cs, так что это пользовательский контроль. Как я могу работать с ним в качестве стандартного управления или что я могу сделать иначе? –

0
[SetUpFixture] 
    public class SETUP_THAT_WILL_GET_CALL_LATER 
    { 
     [OneTimeSetUp] 
     public void OneTimeSetUp() 
     { 
      var applicationDirectory = TestContext.CurrentContext.TestDirectory; 
      var applicationPath = Path.Combine(applicationDirectory, @"..\..\..\, "your debug folder path here", "your application.exe here"); 
      Application = Application.Launch(applicationPath); 

      Thread.Sleep(2000); 

      Window = Application.GetWindow("Title of your application", InitializeOption.WithCache); 
     } 

     [OneTimeTearDown()] 
     public void OneTimeTearDown() 
     { 
      Window.Dispose(); 
      Application.Dispose(); 
     } 

     public static Application Application; 
     public static Window Window; 
    } 

Тогда в тесте

[Test] 
public void yourtest() 
{ 
    var textBox = SETUP_THAT_WILL_GET_CALL_LATER.**Window.Get<TextBox>("Your textbox name here");** 

} 
+0

Мне кажется, что мой код, для запуска приложения и получения окон, но сон тоже не помогает –

+0

hmmm попытаться сделать threadleep (5000) ... если он по-прежнему не работает, я попытаюсь найти некоторые другие решения для вашей проблемы. – user7583356

+0

Добавлены более длинные сны после каждого шага, не помогают –