Каков наилучший способ обмена данными между окном 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 и загруженные события, которые могут дать вам то, что вам нужно.