Каков наилучший способ обмена данными между окном WPF и его пользовательскими элементами управления?

WPF может иногда приводить в бешенство.

У меня есть довольно простое приложение, которое состоит из одного главного окна, содержащего элемент управления tab и несколько вкладок. Мне не понравилась идея иметь код для всех вкладок в одном файле, поэтому я использовал ответ от этот вопрос чтобы разбить каждую вкладку на отдельный пользовательский элемент управления.

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

сначала я попытался получить доступ к родительскому окну в событии controls Loaded и получить ссылку на свойство в главном окне, которое предоставило объект settings, как показано в коде ниже. Этот вид работает, за исключением того, что загруженное событие запускается каждый раз, когда вкладка получает фокус. Кроме того, это событие происходит в конце контроля жизненный цикл, поэтому я не могу привязаться ни к одному из свойств этого объекта в пользовательских элементах управления XAML.

private void MyUserControl_Loaded(object sender, RoutedEventArgs e)
{
    this.ApplicationSettings = ((MainWindow)Window.GetWindow(this)).ApplicationSettings;
}

затем я экспериментировал с передачей данных в конструктор пользовательских элементов управления, но в XAML это невозможно сделать.

учитывая, что это настройки для всего приложения, я мог бы сделать класс ApplicationSettings singleton и ссылаться на него везде, но я бы предпочел не делать этого для целей модульного тестирования.

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

3 ответов


вы можете поместить объект settings в статическое свойство в классе-оболочке (SettingsHolder в этом примере и ссылаться на него приложение через

в XAML:

{Binding SettingName, Source={x:Static local:SettingsHolder.Settings}}

С local являясь пространства имен SettingsHolder класса.

в коде:

var x = SettingsHolder.Settings.SettingName;
SettingsHolder.Settings.SettingName = x;

в объявлении пользовательского элемента управления вы можете просто установить контекст данных для экземпляра объекта, который содержит все, что вам нужно привязать!

<someNamespace:EricsUserControl DataContext="{Binding InstanceOfBindingObject}"/>

затем вы можете получить доступ к свойствам экземпляра этих объектов в пользовательском элементе управления, как обычно.


то, что я делаю, это использовать Frame на Tab и Page на Frame. (но я думаю, что то же самое может применяться к пользовательскому элементу управления). Конструктор запускается только при создании страницы, и вы можете управлять созданием страницы и передавать информацию в конструктор. Страница имеет больше событий жизненного цикла для привязки. Я также использую загруженное событие для создания пользовательского интерфейса (он срабатывает только один раз). Если привязать страницу в XAML он будет срабатывать при запуске приложения, и вы не можете пройти информация. Это создание страницы и отображение ее в диалоговом окне, но эта страница может быть привязана к рамке.

        NavigationWindow winSearchXML;
        using (new WaitCursor())
        {
            winSearchXML = new NavigationWindow();
            winSearchXML.Content = new PageSearchResultsXML(GabeLib.GetSearchXML(GabeLib.enumXMLtype.Flat));
        }
        winSearchXML.ShowDialog();

мне нужно быть честным, что иногда я получаю жизненный цикл на странице, которую я просто не понимаю. Так что прими это с солью. Но дело в том, что у вас есть contructor и загруженные события, которые могут дать вам то, что вам нужно.