Подтвердить что ты не робот

Силовое связывание в WPF

Я пишу тесты, которые будут проверять правильность элементов Binding, указанных в XAML. Они работают до сих пор, единственная проблема заключается в том, что я не знаю, как правильно заставить привязку данных произойти. Удивительно, что недостаточно просто установить что-то в DataContext, привязка не произойдет, пока вы не покажете свой элемент управления/окно. Пожалуйста, не то, что я пишу "unit" -тесты, и я бы хотел не показывать какие-либо окна.

Взгляните на следующий код:

// This is main class in console application where I have all WPF references added
public class Program
{
    [STAThread]
    public static void Main()
    {
        var view = new Window();
        BindingOperations.SetBinding(view, Window.TitleProperty, new Binding("Length"));
        view.DataContext = new int[5];
        //view.Show(); view.Close(); // <-- this is the code I'm trying not to write
        Console.WriteLine(view.Title);
    }
}

Здесь я создаю Окно и помещаю массив в DataContext в это окно. Я привязываю Window.Title к Array.Length, поэтому я ожидаю увидеть номер 5, напечатанный на консоли. Но до тех пор, пока окно Show (строка комментариев) не получит пустую строку. Если я раскомментирую эту строку, тогда я получу желаемый 5 в выводе консоли.

Есть ли способ сделать привязку, не показывая окно? Весьма раздражает смотреть на ~ 20 окон при запуске тестов.

P.S.: Я знаю, что я могу сделать окна более прозрачными и т.д., но я ищу более элегантное решение.

UPDATE Код выше - это упрощенная версия того, что у меня действительно есть. В реальном коде я получаю View (некоторые UIElement с привязками) и object ViewModel. Я не знаю, какая именно привязка была установлена ​​на View, но я все же хочу, чтобы все они были инициализированы.

ОБНОВЛЕНИЕ 2: Отвечая на вопросы относительно того, что я тестирую, и почему. Я не намерен тестировать, что классы, такие как Binding, BindingBase и т.д. Работают как ожидалось, я предполагаю, что они работают. Я пытаюсь проверить, что во всех моих файлах XAML я правильно написал привязки. Поскольку привязки являются строгими типизированными вещами, они не проверяются во время компиляции, и по умолчанию они вызывают только ошибки в окне вывода, которые я иногда пропускаю. Поэтому, если мы возьмем мой пример сверху и если мы сделаем опечатку там в bind: {Binding Lengthhh}, тогда мои тесты уведомят вас о том, что для привязки нет свойства с именем Lengthhh. Поэтому у меня около 100 файлов XAML, и для каждого XAML у меня есть тест (3-5 строк кода), и после запуска моих тестов я знаю для уверенного, что в моем решении нет ошибок привязки.

4b9b3361

Ответ 1

Если вы пытаетесь проверить правильность своего представления, я предлагаю вам проверить ваше мнение: -)

Почему бы не запустить пользовательский интерфейс из unit test и написать код, который проверяет содержимое пользовательского интерфейса после изменения данных.

VS2010 имеет тестирование GUI, или вы можете взглянуть на код таких инструментов, как Snoop.

<ч/" > Изменить следующий комментарий:

Если ВСЕ, что вы хотите сделать, это проверить несколько простых привязок, попробуйте написать статический тест кода, который запускается как событие пост-сборки, используя отражение на моделях просмотров и регулярных выражений на XAML. Добавьте атрибуты в виртуальную машину или используйте файл конфигурации, чтобы ваш тест знал, какой вид получает, который рассматривает модель как DataContext. Сравните имена и типы свойств в View Model со строками привязки в представлении (автоматически для поиска XAML для них) и генерируйте исключение (таким образом, сбой сборки), если строки не совпадают.

Если ваши привязки более сложны (преобразователи, multibindings,...), это может быть несколько сложнее реализовать.

Ответ 2

Связи обновляются диспетчером с DispatcherPriority.DataBind - поэтому, если вы ждете фиктивной задачи с приоритетом SystemIdle, вы уверены, что все ожидающие привязки данных выполняются.

  try
  {
    this.Dispatcher.Invoke(DispatcherPriority.SystemIdle, new Action(() => { }));
  }
  catch
  {
    // Cannot perfom this while Dispatcher in suspended mode
  }

Ответ 3

Я думаю, вы должны сначала установить DataContext, а затем выполнить привязку, например:

view.DataContext = new int[5];
BindingOperations.SetBinding(view, Window.TitleProperty, new Binding("Length"));

Я не уверен, что это реальное решение для вашей общей проблемы, но оно работает в этом случае.

Ответ 4

Я не верю, что привязки Window будут выполняться без вызова Show или ShowDialog, потому что это единственный способ связать его с конвейером/диспетчером пользовательского интерфейса.

Лучше всего было бы установить его как можно менее видимым, потенциально используя метод расширения для очистки вещей:

public static void PokeWindowDispatcher(this Window window)
{
    window.WindowState = WindowState.Minimized;
    window.ShowInTaskbar = false;
    window.Visibility = Visibility.None;

    using (var wait = new ManualResetEvent())
    {
        Action<object, RoutedEventArgs> loaded = (sender, e) => wait.Set();
        window.Loaded += loaded;
        try
        {
            window.Show();
            wait.WaitOne();
        }
        finally
        {
            window.Loaded -= loaded;
            window.Close();
        }
    }
}

Ответ 5

У меня была такая же проблема, и из шестизначных переменных мне дали идею. Это очень просто. Я использую WPF в приложении WinForms, поэтому я использую элемент управления ElementHost для размещения элементов управления Wpf в элементе управления WinForms. Чтобы обеспечить инициализацию управления WinForms, вы можете просто прочитать значение Handle (на самом деле это Windows HWND), и это заставит элемент управления полностью инициализировать себя, включая дочерние ElementHost и всю работу по связыванию Wpf. Я не пытался выполнять одно и то же для чистого управления Wpf. Но вы можете легко использовать ElementHost для инициализации своих элементов управления Wpf следующим образом:

var el = new ElementHost();
var p = new TextBlock();
p.DataContext = new { Data = "1234" };
p.SetBinding(TextBlock.TextProperty, "Data");
el.Child = p;
var t = el.Handle;
Debug.Assert(p.Text == "1234");

PS: Найдено, что все работает лучше, если вы сначала установите DataContext и только затем принудительно создаете Handle (как и в моем примере). Но, я думаю, это уже относится к вам, поэтому не должно быть проблемой.

Ответ 6

Вы пытались использовать IsDataBound

http://msdn.microsoft.com/en-us/library/system.windows.data.bindingoperations.isdatabound.aspx

Также проверьте это:

System.Windows.Interop.WindowInteropHelper helper = new System.Windows.Interop.WindowInteropHelper(view).EnsureHandle();

http://msdn.microsoft.com/en-us/library/system.windows.interop.windowinterophelper.ensurehandle.aspx

Мой другой вопрос - почему вы пытаетесь сделать UNIT test на том, что уже было технически проверено? Кстати, я не критикую, просто хочу понять немного лучше.

Ответ 7

Не уверен, но может быть что-то подобное будет работать?

view.GetBindingExpression(Window.TitleProperty).UpdateTarget();