解决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:

基类:

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);
    }
}

 

    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
    }

  切换子控件:

……    
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;
……

  

posted @ 2025-02-18 11:57  dyfisgod  阅读(79)  评论(0)    收藏  举报