В моем приложении WPF у меня так много UC и элементов управления, что я хочу предотвратить их загрузку и выгрузку после повторного подключения пользователя к rdc. Я провел много исследований, чтобы решить эту проблему, но ничего не работает.
Это происходит при повторном подключении к сеансу удаленного рабочего стола.
Элементы управления выгружаются, а затем перезагружаются
Элементы управления в DataTemplates завершаются и воссоздаются. есть ли способ предотвратить загрузку и выгрузку элементов управления
мое приложение работает на .NET Framework версии 4.6
вот мой код
public uc()
{
uc.Loaded +=somemethod;
}
somemethod(){
TextBox tb = new TextBox();
this.AddChild(tb); // after getting called again it adds another textbox
}
после повторного подключения первая попадающая точка останова находится в конструкторе, и я не знаю, как ее отлаживать дальше, потому что трассировка стека показывает только [внешний код] до этого.
причина в том, что мы везде используем один и тот же UC для заголовка и просто меняем дочерние элементы в соответствии с изменениями страницы.
Если бы вы могли быть более конкретными, я мог бы предложить правильное решение. В настоящее время похоже, что у вас есть UserControl, в котором размещается динамический контент. Это содержимое меняется в зависимости от текущего контекста. В этом случае вы должны определить это динамическое содержимое внутри DataTemplate. Если бы вы могли расширить свой пример, чтобы показать реальный вариант использования, это было бы очень полезно.
Когда это важно, я использую флаг (например, bool isInitialized = false;), который проверяется и устанавливается в событии Loaded. Если флаг ложный; процедура запускается и устанавливает флаг в значение true, поэтому с этого момента она обходит Loaded. Часто флаг «проверяют» там, где нужно, но устанавливают его только в «родительском» событии Loaded, поскольку оно срабатывает последним. «Решение» без флага состоит в том, чтобы продолжать ссылаться на родительское свойство «IsLoaded»; предполагая, что «это» не перезагружается постоянно.





В общем, добавление элементов управления в визуальное дерево из кода программной части обычно приводит к проблемам или излишне сложному коду. Это редко бывает решением
В вашем случае, если вы хотите, чтобы UserControl предоставлял статический контент во всех своих экземплярах и динамический контент, вам следует переопределить значение по умолчанию ControlTemplate.
ControlTemplate содержит статический контент (конечно, он может быть привязан к свойствам UserControl). Но клиент UserControl не может его изменить (без переопределения ControlTemplate). Клиент добавляет свой контент как обычно, устанавливая свойство UserControl.Content.
РазделыUserControl.xaml
<UserControl>
<UserControl.Template>
<ControlTemplate TargetType = "local:PrintableContentHost">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height = "Auto" /> <!-- Header row -->
<RowDefinition /> <!-- Content row -->
</Grid.RowDefinitions>
<Grid Grid.Row = "0">
<TextBlock Text = "I'm header content" />
</Grid>
<Grid Grid.Row = "1">
<ContentPresenter />
</Grid>
</Grid>
</ControlTemplate>
</UserControl.Template>
</UserControl>
Теперь вы можете использовать SectionsUserControl на нескольких страницах, где содержимое заголовка остается прежним, а меняется только фактическое содержимое страницы.
Чтобы предоставить динамический контент, вы можете:
Пример 1): определите DataTemplate и назначьте модель данных UserControl.Content (например, класс модели представления в контексте MVVM) или
Пример 2): установите встроенное свойство UserControl.Content
PageModel.cs
class PageModel : INotifyPropertyChnaged
{
public string PageText => "This is individual page content that is displayed below the header";
}
App.xaml
<ResourceDictionary>
<DataTemplate x:Key = "PageContentTemplate"
DataType = "{x:Type PageModel}">
<TextBlock Text = "{Binding PageText}" />
</DataTemplate>
<ResourceDictionary>
MainWindow.xaml
<Window>
<!--
The ContentTemplate property is explicitly set in this example to
highlight the concept.
If the DataTemplate is implicit (keyless) then the template would be
automatically loaded by WPF.
-->
<SectionsUserControl ContentTemplate = "{StaticResource PageContentTemplate}">
<SectionsUserControl.Content> <!-- You can bind the PageModel to the SectionsUserControl.Content property -->
<PageModel />
</SectionsUserControl.Content>
</SectionsUserControl>
</Window>
MainWindow.xaml
<Window>
<SectionsUserControl>
<SectionsUserControl.Content>
<TextBlock Text = "This is individual page content that is displayed below the header" />
</SectionsUserControl.Content>
</SectionsUserControl>
</Window>
Согласно комментарию @GerrySchmitz, я использовал флаг, чтобы отслеживать, загружен элемент управления или нет, и установил его соответствующим образом. Однако в моем приложении некоторые пользовательские элементы управления (UC) имеют главное окно в качестве непосредственного родительского элемента, тогда как другие имеют страницу или фрейм в качестве родительского элемента. После долгих раздумий и попыток разных решений я наконец создал метод, который эффективно предотвращает проблему. Хотя это не прямое решение, это трюк, который помогает избежать проблемы. Вот код для этого
В mainwindow.xaml.cs
private bool IsDisconnect = false; // flag to check whether session is disconnected or not.
private int counter;// to check the number of controls that are getting loaded or unloaded
public MainWindow()
{
SystemEvents.SessionSwitch += new SessionSwitchEventHandler(SystemEvents_SessionSwitch);
EventManager.RegisterClassHandler(typeof(UserControl), UserControl.LoadedEvent, new RoutedEventHandler(UserControlLoaderUnloaderHandler));
EventManager.RegisterClassHandler(typeof(UserControl), UserControl.UnloadedEvent, new RoutedEventHandler(UserControlLoaderUnloaderHandler));
EventManager.RegisterClassHandler(typeof(Page), Page.LoadedEvent, new RoutedEventHandler(PageLoaderUnLoaderHandler));
EventManager.RegisterClassHandler(typeof(Page), Page.UnloadedEvent, new RoutedEventHandler(PageLoaderUnLoaderHandler));
//rest of the code
}
private void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
{
if (e.Reason == SessionSwitchReason.) IsDisconnect = true;
}
private void UserControlLoaderUnloaderHandler(object sender, RoutedEventArgs e)
{
var userControl = sender as UserControl;
if (userControl != null && IsDisconnect)
{
e.Handled = true;
if (e.RoutedEvent == FrameworkElement.UnloadedEvent) counter++;
if (e.RoutedEvent == FrameworkElement.LoadedEvent) counter--;
}
if (IsDisconnect && counter == 0) IsDisconnect = false;
}
private void PageLoaderUnLoaderHandler(object sender, RoutedEventArgs e)
{
var page = sender as Page;
if (page != null && IsDisconnect)
{
e.Handled = true;
if (e.RoutedEvent == FrameworkElement.UnloadedEvent) counter++;
if (e.RoutedEvent == FrameworkElement.LoadedEvent) counter--;
}
if (IsDisconnect && counter == 0) IsDisconnect = false;
}
Когда RemoteDisconnect является причиной переключения сеанса, метод SystemEvents_SessionSwitch устанавливает флаг IsDisconnect в true..
а в методах UserControlLoaderUnloaderHandler и PageLoaderUnLoaderHandler всякий раз, когда пользовательский элемент управления (UC) или страница выгружаются, то же количество из них в конечном итоге необходимо будет загрузить снова после удаленного отключения. Чтобы предотвратить вызов метода Loaded в UC или Pages, мы устанавливаем e.Handled = true;
Увеличивая счетчик при выгрузке UC и страниц и уменьшая его при загрузке, мы можем отслеживать, сколько UC и страниц загружается и выгружается. Мы используем условие (IsDisconnect && counter==0), чтобы установить для флага IsDisconnect значение false после того, как все UC и страницы были загружены обратно или когда счетчик достигнет нуля.
До сих пор это решение было эффективным. Вы можете изменить его, изменив элементы управления и внося необходимые изменения соответствующим образом.
Если вы добавите элементы управления в код XAML, этой проблемы не возникнет. Есть ли причина добавлять элементы управления в макет из кода программной части?