372 lines
15 KiB
C#
372 lines
15 KiB
C#
|
|
//using Prism.Ioc;
|
|||
|
|
//using System;
|
|||
|
|
//using System.Windows;
|
|||
|
|
//using System.Windows.Controls;
|
|||
|
|
//using System.Windows.Threading;
|
|||
|
|
|
|||
|
|
//namespace YY.Admin.Views.Control
|
|||
|
|
//{
|
|||
|
|
// /// <summary>
|
|||
|
|
// /// TabContentView.xaml 的交互逻辑
|
|||
|
|
// /// </summary>
|
|||
|
|
// public partial class TabContentView : UserControl
|
|||
|
|
// {
|
|||
|
|
// public TabContentView()
|
|||
|
|
// {
|
|||
|
|
// InitializeComponent();
|
|||
|
|
// this.Loaded += TabContentView_Loaded;
|
|||
|
|
// this.Unloaded += TabContentView_Unloaded;
|
|||
|
|
// }
|
|||
|
|
|
|||
|
|
// private bool _navigated = false;
|
|||
|
|
|
|||
|
|
// private void TabContentView_Loaded(object sender, RoutedEventArgs e)
|
|||
|
|
// {
|
|||
|
|
// try
|
|||
|
|
// {
|
|||
|
|
// if (string.IsNullOrWhiteSpace(RegionName))
|
|||
|
|
// return;
|
|||
|
|
|
|||
|
|
// var regionManager = ContainerLocator.Current.Resolve<IRegionManager>();
|
|||
|
|
|
|||
|
|
// // 把内部 ContentControl 注册为 region(基于 RegionName)
|
|||
|
|
// RegionManager.SetRegionName(PART_ContentHost, RegionName);
|
|||
|
|
// RegionManager.SetRegionManager(PART_ContentHost, regionManager);
|
|||
|
|
|
|||
|
|
// // 延迟导航,确保 region 真正注册到 RegionManager 并且模板生成为止
|
|||
|
|
// if (!_navigated && !string.IsNullOrEmpty(ViewName))
|
|||
|
|
// {
|
|||
|
|
// Dispatcher.BeginInvoke(new Action(() =>
|
|||
|
|
// {
|
|||
|
|
// try
|
|||
|
|
// {
|
|||
|
|
// // 再次检查 region 是否存在并执行导航
|
|||
|
|
// if (regionManager.Regions.ContainsRegionWithName(RegionName))
|
|||
|
|
// {
|
|||
|
|
// regionManager.RequestNavigate(RegionName, ViewName);
|
|||
|
|
// }
|
|||
|
|
// else
|
|||
|
|
// {
|
|||
|
|
// // 如果 region 仍然不存在,尝试 RequestNavigate(Prism 通常会创建 region)
|
|||
|
|
// regionManager.RequestNavigate(RegionName, ViewName);
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
// catch (Exception ex)
|
|||
|
|
// {
|
|||
|
|
// System.Diagnostics.Debug.WriteLine($"TabContentView 导航异常: {ex.Message}");
|
|||
|
|
// }
|
|||
|
|
// }), DispatcherPriority.Background);
|
|||
|
|
|
|||
|
|
// _navigated = true;
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
// catch (Exception ex)
|
|||
|
|
// {
|
|||
|
|
// System.Diagnostics.Debug.WriteLine($"TabContentView_Loaded 出错: {ex.Message}");
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
|
|||
|
|
// private void TabContentView_Unloaded(object sender, RoutedEventArgs e)
|
|||
|
|
// {
|
|||
|
|
// try
|
|||
|
|
// {
|
|||
|
|
// if (!string.IsNullOrWhiteSpace(RegionName))
|
|||
|
|
// {
|
|||
|
|
// var regionManager = ContainerLocator.Current.Resolve<IRegionManager>();
|
|||
|
|
// if (regionManager.Regions.ContainsRegionWithName(RegionName))
|
|||
|
|
// {
|
|||
|
|
// var region = regionManager.Regions[RegionName];
|
|||
|
|
// region.RemoveAll();
|
|||
|
|
// regionManager.Regions.Remove(RegionName);
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
// catch (Exception ex)
|
|||
|
|
// {
|
|||
|
|
// System.Diagnostics.Debug.WriteLine($"TabContentView_Unloaded 清理异常: {ex.Message}");
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
|
|||
|
|
// #region RegionName DP
|
|||
|
|
// public static readonly DependencyProperty RegionNameProperty =
|
|||
|
|
// DependencyProperty.Register(nameof(RegionName), typeof(string), typeof(TabContentView), new PropertyMetadata(null));
|
|||
|
|
|
|||
|
|
// public string RegionName
|
|||
|
|
// {
|
|||
|
|
// get => (string)GetValue(RegionNameProperty);
|
|||
|
|
// set => SetValue(RegionNameProperty, value);
|
|||
|
|
// }
|
|||
|
|
// #endregion
|
|||
|
|
|
|||
|
|
// #region ViewName DP
|
|||
|
|
// public static readonly DependencyProperty ViewNameProperty =
|
|||
|
|
// DependencyProperty.Register(nameof(ViewName), typeof(string), typeof(TabContentView), new PropertyMetadata(null));
|
|||
|
|
|
|||
|
|
// public string ViewName
|
|||
|
|
// {
|
|||
|
|
// get => (string)GetValue(ViewNameProperty);
|
|||
|
|
// set => SetValue(ViewNameProperty, value);
|
|||
|
|
// }
|
|||
|
|
// #endregion
|
|||
|
|
// }
|
|||
|
|
//}
|
|||
|
|
using Prism.Ioc;
|
|||
|
|
using System;
|
|||
|
|
using System.Diagnostics;
|
|||
|
|
using System.Windows;
|
|||
|
|
using System.Windows.Controls;
|
|||
|
|
using System.Windows.Threading;
|
|||
|
|
|
|||
|
|
namespace YY.Admin.Views.Control
|
|||
|
|
{
|
|||
|
|
public partial class TabContentView : UserControl
|
|||
|
|
{
|
|||
|
|
public TabContentView()
|
|||
|
|
{
|
|||
|
|
InitializeComponent();
|
|||
|
|
|
|||
|
|
this.Loaded += TabContentView_Loaded;
|
|||
|
|
this.Unloaded += TabContentView_Unloaded;
|
|||
|
|
this.IsVisibleChanged += TabContentView_IsVisibleChanged;
|
|||
|
|
this.DataContextChanged += TabContentView_DataContextChanged;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private bool _navigated = false;
|
|||
|
|
private IRegionManager _regionManager;
|
|||
|
|
private DispatcherOperation _pendingNavigationOp;
|
|||
|
|
|
|||
|
|
#region DPs
|
|||
|
|
public static readonly DependencyProperty RegionNameProperty =
|
|||
|
|
DependencyProperty.Register(nameof(RegionName), typeof(string), typeof(TabContentView), new PropertyMetadata(null, OnRegionOrViewNameChanged));
|
|||
|
|
|
|||
|
|
public string RegionName
|
|||
|
|
{
|
|||
|
|
get => (string)GetValue(RegionNameProperty);
|
|||
|
|
set => SetValue(RegionNameProperty, value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static readonly DependencyProperty ViewNameProperty =
|
|||
|
|
DependencyProperty.Register(nameof(ViewName), typeof(string), typeof(TabContentView), new PropertyMetadata(null, OnRegionOrViewNameChanged));
|
|||
|
|
|
|||
|
|
public string ViewName
|
|||
|
|
{
|
|||
|
|
get => (string)GetValue(ViewNameProperty);
|
|||
|
|
set => SetValue(ViewNameProperty, value);
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
private void TabContentView_Loaded(object sender, RoutedEventArgs e)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (string.IsNullOrWhiteSpace(RegionName))
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
_regionManager = ContainerLocator.Current.Resolve<IRegionManager>();
|
|||
|
|
|
|||
|
|
// 确保 region/manager 设置在后续导航前准备好(但不要重复注册 region 这里)
|
|||
|
|
// We will call PrepareRegionForRegistration inside EnsureNavigateIfNeeded before actual registration.
|
|||
|
|
EnsureNavigateIfNeeded();
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.WriteLine($"TabContentView_Loaded 出错: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void TabContentView_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
|||
|
|
=> EnsureNavigateIfNeeded();
|
|||
|
|
|
|||
|
|
private void TabContentView_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
|||
|
|
=> EnsureNavigateIfNeeded();
|
|||
|
|
|
|||
|
|
private void EnsureNavigateIfNeeded()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (_navigated)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
if (string.IsNullOrWhiteSpace(RegionName) || string.IsNullOrWhiteSpace(ViewName))
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
if (!IsLoaded || !IsVisible)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
if (_regionManager == null)
|
|||
|
|
_regionManager = ContainerLocator.Current.Resolve<IRegionManager>();
|
|||
|
|
|
|||
|
|
// 在注册 region 之前准备 host(清理旧 region 与清空 Content),避免 Prism 抛 Content 非空异常
|
|||
|
|
PrepareRegionForRegistration();
|
|||
|
|
|
|||
|
|
// 取消之前挂起的导航(保证最后一次胜出)
|
|||
|
|
if (_pendingNavigationOp != null && _pendingNavigationOp.Status == DispatcherOperationStatus.Pending)
|
|||
|
|
{
|
|||
|
|
Debug.WriteLine($"取消挂起导航: region={RegionName}, view={ViewName}");
|
|||
|
|
_pendingNavigationOp.Abort();
|
|||
|
|
_pendingNavigationOp = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var desiredView = ViewName;
|
|||
|
|
var desiredRegion = RegionName;
|
|||
|
|
|
|||
|
|
_pendingNavigationOp = Dispatcher.BeginInvoke(new Action(() =>
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (_regionManager == null)
|
|||
|
|
_regionManager = ContainerLocator.Current.Resolve<IRegionManager>();
|
|||
|
|
|
|||
|
|
// 现在把 PART_ContentHost 注册为一个 region(设置 RegionName/RegionManager)
|
|||
|
|
// 注意:如果前面清理正确,这里不会再触发 ContentControl already has content 错误
|
|||
|
|
RegionManager.SetRegionName(PART_ContentHost, desiredRegion);
|
|||
|
|
RegionManager.SetRegionManager(PART_ContentHost, _regionManager);
|
|||
|
|
|
|||
|
|
Debug.WriteLine($"开始 RequestNavigate -> region={desiredRegion}, view={desiredView}");
|
|||
|
|
|
|||
|
|
_regionManager.RequestNavigate(desiredRegion, desiredView, result =>
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (result.Success == true)
|
|||
|
|
{
|
|||
|
|
_navigated = true;
|
|||
|
|
Debug.WriteLine($"导航成功: region={desiredRegion}, view={desiredView}");
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
_navigated = false;
|
|||
|
|
Debug.WriteLine($"导航失败: region={desiredRegion}, view={desiredView}, error={result.Exception?.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
_navigated = false;
|
|||
|
|
Debug.WriteLine($"导航回调异常: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.WriteLine($"调度导航异常: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
_pendingNavigationOp = null;
|
|||
|
|
}
|
|||
|
|
}), DispatcherPriority.Background);
|
|||
|
|
|
|||
|
|
Debug.WriteLine($"调度导航: Region={RegionName}, View={ViewName}, Loaded={IsLoaded}, Visible={IsVisible}, navigated={_navigated}");
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.WriteLine($"EnsureNavigateIfNeeded 异常: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 在注册 region 之前清理宿主控件与 RegionManager 中可能残留的 region。
|
|||
|
|
/// 这一步是防止 Prism 在 adapt 时因为 ContentControl.Content 非空而抛异常。
|
|||
|
|
/// </summary>
|
|||
|
|
private void PrepareRegionForRegistration()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// 如果 RegionManager 中已存在同名 region,则先移除它(并 RemoveAll 内容)
|
|||
|
|
if (_regionManager != null && _regionManager.Regions.ContainsRegionWithName(RegionName))
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var existing = _regionManager.Regions[RegionName];
|
|||
|
|
existing.RemoveAll();
|
|||
|
|
_regionManager.Regions.Remove(RegionName);
|
|||
|
|
Debug.WriteLine($"已移除旧 region: {RegionName}");
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.WriteLine($"移除旧 region 发生异常: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果宿主 ContentControl 已经有内容,清空它(很关键)
|
|||
|
|
if (PART_ContentHost != null && PART_ContentHost.Content != null)
|
|||
|
|
{
|
|||
|
|
Debug.WriteLine($"清空 PART_ContentHost.Content (原内容类型: {PART_ContentHost.Content.GetType().Name})");
|
|||
|
|
PART_ContentHost.Content = null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.WriteLine($"PrepareRegionForRegistration 异常: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void TabContentView_Unloaded(object sender, RoutedEventArgs e)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// 取消挂起导航
|
|||
|
|
if (_pendingNavigationOp != null && _pendingNavigationOp.Status == DispatcherOperationStatus.Pending)
|
|||
|
|
{
|
|||
|
|
_pendingNavigationOp.Abort();
|
|||
|
|
_pendingNavigationOp = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 清理 region 与宿主内容
|
|||
|
|
if (!string.IsNullOrWhiteSpace(RegionName))
|
|||
|
|
{
|
|||
|
|
var rm = _regionManager ?? ContainerLocator.Current.Resolve<IRegionManager>();
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (rm != null && rm.Regions.ContainsRegionWithName(RegionName))
|
|||
|
|
{
|
|||
|
|
var region = rm.Regions[RegionName];
|
|||
|
|
region.RemoveAll();
|
|||
|
|
rm.Regions.Remove(RegionName);
|
|||
|
|
Debug.WriteLine($"卸载并移除 region: {RegionName}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.WriteLine($"TabContentView_Unloaded 清理 region 异常: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (PART_ContentHost != null && PART_ContentHost.Content != null)
|
|||
|
|
{
|
|||
|
|
PART_ContentHost.Content = null;
|
|||
|
|
Debug.WriteLine($"Unloaded: 清空 PART_ContentHost.Content");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.WriteLine($"TabContentView_Unloaded 清理异常: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
_navigated = false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static void OnRegionOrViewNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|||
|
|
{
|
|||
|
|
if (d is TabContentView tc)
|
|||
|
|
{
|
|||
|
|
// 新参数到来,允许再次导航
|
|||
|
|
tc._navigated = false;
|
|||
|
|
|
|||
|
|
// 取消旧挂起导航
|
|||
|
|
if (tc._pendingNavigationOp != null && tc._pendingNavigationOp.Status == DispatcherOperationStatus.Pending)
|
|||
|
|
{
|
|||
|
|
tc._pendingNavigationOp.Abort();
|
|||
|
|
tc._pendingNavigationOp = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 尝试导航(这一调用会在 Loaded/可见时真正执行)
|
|||
|
|
tc.EnsureNavigateIfNeeded();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|