基于C#WPF和OpencvSharp开发的图像处理系统——2.多页面切换

6 阅读2分钟

使用多个Radiobutton来切换不同的UserControl来实现。

Radiobutton的样式已在上篇文章中给出。

Service代码

/// <summary>
/// 页面导航注册服务类
/// </summary>
public class SimpleNavigationService
{
    #region 懒加载实现单例

    private static readonly Lazy<SimpleNavigationService> _instance = new Lazy<SimpleNavigationService>(() => new SimpleNavigationService());

    public static SimpleNavigationService Instance => _instance.Value;

    private SimpleNavigationService()
    {
    }

    #endregion 懒加载实现单例

    private readonly Dictionary<PageEnum, UserControl> _instances = new Dictionary<PageEnum, UserControl>();

    /// <summary>
    /// 注册界面
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    public void Register<T>(PageEnum key) where T : UserControl, new()
    {
        _instances[key] = new T();
    }

    public UserControl Navigate(PageEnum key)
    {
        if (_instances.TryGetValue(key, out UserControl instance))
        {
            return instance;
        }

        throw new ArgumentException($"页面未注册: {key}");
    }
}

其中只有注册页面和切换页面。

ViewModel如下:

public class NavigationViewModel : ViewModelBase
{
    public NavigationViewModel()
    {
        NavigateCommand = new Command<PageEnum>(Navigate);

        // 注册页面
        SimpleNavigationService? simpleNavigationService = SimpleNavigationService.Instance;
        simpleNavigationService.Register<MainUserControl>(PageEnum.MainPage);
        simpleNavigationService.Register<ImgCalUserControl>(PageEnum.ImgCalPage);
        simpleNavigationService.Register<FeatureMatchUserControl>(PageEnum.FeatureMatchPage);
        simpleNavigationService.Register<FeatureDetectUserControl>(PageEnum.FeatureDetectPage);
        simpleNavigationService.Register<MorphologicalOperationsControl>(PageEnum.MorphologicalPage);
        simpleNavigationService.Register<TextUserControl>(PageEnum.TextPage);
        simpleNavigationService.Register<FloodFillUserControl>(PageEnum.FloodFillPage);
        simpleNavigationService.Register<MosaicUserControl>(PageEnum.MosaicPage);
        simpleNavigationService.Register<FaceRecognitionUserControl>(PageEnum.FaceRecognitionPage);

        //设置默认界面
        CurrentPage = SimpleNavigationService.Instance.Navigate(PageEnum.MainPage);
    }

    private object _currentPage;

    /// <summary>
    /// 当前页面
    /// </summary>
    public object CurrentPage
    {
        get => _currentPage;
        set
        {
            _currentPage = value;
            OnPropertyChanged();
        }
    }

    /// <summary>
    /// 切换界面 命令
    /// </summary>
    public ICommand NavigateCommand
    {
        get;
    }

    /// <summary>
    /// 切换界面
    /// </summary>
    /// <param name="dstPage"></param>
    private void Navigate(PageEnum dstPage)
    {
        // 用属性赋值
        CurrentPage = SimpleNavigationService.Instance.Navigate(dstPage);
    }
}

注册界面的方法可以放到程序入口。

页面的枚举:

public enum PageEnum
 {
     [Description("主界面")]
     MainPage = 0,

     [Description("算数运算")]
     ImgCalPage,

     [Description("特征匹配")]
     FeatureMatchPage,

     [Description("特征检测")]
     FeatureDetectPage,

     [Description("形态学操作")]
     MorphologicalPage,

     [Description("文本操作")]
     TextPage,

     [Description("水漫操作")]
     FloodFillPage,

     [Description("马赛克")]
     MosaicPage,

     [Description("人脸识别")]
     FaceRecognitionPage,
 }

记得添加Description,可以直接在界面xaml上直接绑定显示,直接采用ItemsControl进行绑定枚举所有的成员,而不用定义多个RadioButton。 xaml文件绑定:

<ItemsControl ItemsSource="{Binding Source={StaticResource PageEnumValues}}">
     <ItemsControl.ItemTemplate>
         <DataTemplate>
             <RadioButton
                 Style="{StaticResource MenuBtnStyle}"
                 Content="{Binding Path=., Converter={StaticResource enumDesConverter}}"
                 IsChecked="{Binding Path=., Converter={StaticResource enumFirstToBoolConverter}}"
                 CommandParameter="{Binding Path=.}"
                 Command="{Binding DataContext.NavigationViewModel.NavigateCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
                 GroupName="PageEnumGroup" />
         </DataTemplate>
     </ItemsControl.ItemTemplate>
 </ItemsControl>

其中需要在主xaml上定义资源

<ObjectDataProvider x:Key="PageEnumValues" MethodName="GetValues" ObjectType="{x:Type sys:Enum}">
     <ObjectDataProvider.MethodParameters>
         <x:Type TypeName="models:PageEnum" />
     </ObjectDataProvider.MethodParameters>
 </ObjectDataProvider>

转换器 枚举->枚举描述

internal class EnumToDescriptionConverter : IValueConverter
 {
     public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
         if (value is Enum enumValue)
         {
             return enumValue.GetDescription();
         }
         return value?.ToString() ?? string.Empty;
     }

     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
     {
         throw new NotImplementedException();
     }
 }

转换器 枚举-> 布尔值

internal class EnumFirstToBoolConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value.GetType().IsEnum == true)
            {
                Type enumType = value.GetType();
                var firstValue = Enum.GetValues(enumType).Cast<object>().First();
                return value.Equals(firstValue);
            }
            return false;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

根据其枚举值是否是第一个 来设置Radiobutton初始是不是选中状态,用来设置默认界面。

界面上用来显示不同的界面即不同用户控件。

<ContentPresenter Grid.Column="1" Content="{Binding NavigationViewModel.CurrentPage}" />

添加新的界面的时候只需要 在PageEnum中添加项 和 在SimpleNavigationService中注册对应界面即可。不需要在修改xaml中的东西。