解决wpf,caliburn.micro框架,重复切换至某个ContentControl后,该界面所有绑定事件突然无效问题
很奇怪的问题,原因不明,多见于 <ContentControl Grid.Row="3" Grid.Column="2" cal:View.Model="{Binding Content}"/> 此种绑定场景下,对Content进行不同viewmodel的赋值,来达到切换界面内容的目的
解决办法:
换个思路,创建ItemsControl,包含所有要使用的子控件,使其中需要显示(激活)的子控件显示,其他则隐藏
View:
<ItemsControl Grid.Row="3" Grid.Column="2" ItemsSource="{Binding Items}" Focusable="False" Height="{Binding ElementName=MainParent,Path=ActualHeight}" Width="{Binding ElementName=MainParent,Path=ActualWidth}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <VirtualizingStackPanel VirtualizingStackPanel.VirtualizationMode="Recycling" IsVirtualizing="True" VirtualizingPanel.ScrollUnit ="Pixel"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <ContentControl cal:View.Model="{Binding IsAsync=True}"> <ContentControl.Visibility> <MultiBinding Converter="{StaticResource MultiCompareToVisibilityConverter}"> <Binding /> <Binding Path="DataContext.ActiveItem" RelativeSource="{RelativeSource AncestorType={x:Type ItemsControl}}"/> </MultiBinding> </ContentControl.Visibility> </ContentControl> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
ViewModel:
基类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public abstract class ActiveViewModel : BaseViewModel { /// <summary> /// 设置显示页面 /// </summary> /// <param name="screen"></param> /// <returns></returns> public Task SetActiveItem(Caliburn.Micro.Screen screen = null ) { if ( this .ActiveItem == screen) return Task.Run(() => this .Get<MainViewModel>().IsBusy = false ); else return Task.Run(async () => await this .ActivateItemAsync(screen)).ContinueWith(__ => this .Get<MainViewModel>().IsBusy = false ); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | public class BaseViewModel : Conductor< object >.Collection.OneActive { #region private fields /// <summary> /// 窗体管理器 /// </summary> protected readonly IWindowManager windowManager; #endregion #region consturtor static BaseViewModel() { // Caliburn.Micro(CM) 穿过 Popup 绑定方法 http://www.cnblogs.com/gaoshang212/p/4203929.html ActionMessage.SetMethodBinding = context => { var source = context.Source; System.Windows.DependencyObject currentElement = source; while (currentElement != null ) { if (Caliburn.Micro.Action.HasTargetSet(currentElement)) { var target = Message.GetHandler(currentElement); if (target != null ) { var method = ActionMessage.GetTargetMethod(context.Message, target); if (method != null ) { context.Method = method; context.Target = target; context.View = currentElement; return ; } } else { context.View = currentElement; return ; } } //修改部分 Begin var pElement = System.Windows.Media.VisualTreeHelper.GetParent(currentElement); if (pElement == null && currentElement.GetType().Name.Equals( "PopupRoot" , System.StringComparison.OrdinalIgnoreCase)) { if (currentElement is System.Windows.FrameworkElement ef) pElement = ef.Parent; } currentElement = pElement; //End } if (source != null && source.DataContext != null ) { var target = source.DataContext; var method = ActionMessage.GetTargetMethod(context.Message, target); if (method != null ) { context.Target = target; context.Method = method; context.View = source; } else { source.Visibility = System.Windows.Visibility.Collapsed; } } }; } /// <summary> /// 构造函数 /// </summary> public BaseViewModel() => this .windowManager = this .Get<IWindowManager>(); /// <summary> /// 构造函数 /// </summary> /// <param name="windowManager"></param> public BaseViewModel(IWindowManager windowManager) { this .windowManager = windowManager; } #endregion #region public methods /// <summary> /// 根据类型和名称获取实例对象 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="name"></param> /// <returns></returns> public virtual T Get<T>( string name = null ) => (T)IoC.Get<T>(name); /// <summary> /// 提示消息 /// </summary> /// <param name="message">提示内容</param> /// <param name="isAsk">是否询问消息</param> /// <returns></returns> public bool ? ShowMessage( string message, MessageType type = MessageType.正常) => MessageBoxExt.ShowMessage(message, type); /// <summary> /// /// </summary> /// <param name="viewModel"></param> /// <returns></returns> public void ShowWindow(BaseViewModel viewModel, bool dialog = true ) { if (windowManager== null ||viewModel== null ) return ; if (dialog) windowManager.ShowDialogAsync(viewModel); else windowManager.ShowWindowAsync(viewModel); } #endregion } |
切换子控件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | …… case ProcessStage.Camera: if (cameraViewModel== null ) cameraViewModel= this .Get<CameraViewModel>(); this .SetActiveItem(cameraViewModel); cameraViewModel.StartCamera(); break ; case ProcessStage.Photo: if (photoViewModel== null ) photoViewModel= this .Get<PhotoViewModel>(); this .SetActiveItem(photoViewModel); cameraViewModel.StopCamera(); break ; …… |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用