时隔1个月,2015/06/17走进新的环境。
最近一个星期在学习仿Word菜单栏的WPF实现方式,废话不多说,先看一下效果。
打开界面后,默认选中【市场A】,A对应的菜单栏,如上图,
选择【市场B】后讲改变菜单栏,和B相应的界面。
要实现上述的功能,要怎么解决?
实际上,每个界面都可以看成有三部分组成,顶部的DEV.RibbonControl,左侧的DEV.NavbarControl,和中间显示主要界面C部分。
NavBarControl中包含多个NavBarItem,当切换NavBarItem时,就加载相应的子界面到C处。但,除了MainWindow完整包含这几个部分外,其他子界面都不一定。
下面,就围绕这3个部分展开。
1、MainWindow.xaml
RibbonStyle="Office2010" x:Name="ribbon" AllowCustomization="False">
SelectedItem="{Binding SelectedModuleInfo, Mode=TwoWay}" ItemsSource="{Binding Path=ModuleGroups}">
MainWindow.cs
namespace WPFOptimizeTry
{
///
/// MainWindow.xaml 的交互逻辑
///
public partial class MainWindow : DXRibbonWindow
{
public virtual FrameworkElement BindContent { get; set; }
public MainWindow()
{
InitializeComponent();
if (Height > SystemParameters.VirtualScreenHeight || Width > SystemParameters.VirtualScreenWidth)
WindowState = WindowState.Maximized;
DevExpress.Utils.About.UAlgo.Default.DoEventObject(DevExpress.Utils.About.UAlgo.kDemo, DevExpress.Utils.About.UAlgo.pWPF, this);
}
void OnDocumentFrameNavigating(object sender, NavigatingEventArgs e)
{
if (e.Cancel) return;
//在Show命令中触发导航事件,在导航时加载子界面,
Type type = Type.GetType(new MainWindow().GetType().Namespace + "." + e.Parameter.ToString(), true, true);
var temp = Activator.CreateInstance(type);
NavigationFrame frame = (sender as NavigationFrame);
frame.Content = temp;
//到这里其实已经加载页面完毕,如果不添加SetMergeWith语句,会将子界面整个加载到C区,再与主界面合并,肉眼能够看到整个程序变化的过程。
//使用SetMergeWith可以使整个过度很平滑,会让你觉得一开始菜单就在菜单的位置。
FrameworkElement oldContent = (FrameworkElement)frame.Content;
if (oldContent != null)
{
RibbonMergingHelper.SetMergeWith(oldContent, ribbon);
RibbonMergingHelper.SetMergeStatusBarWith(oldContent, statusBar);
}
//下面这句话不可缺少,
e.Cancel = true;
}
}
}
MainWindowViewModel.cs
namespace WPFOptimizeTry
{
public class MainWindowViewModel
{
public virtual IEnumerable ModuleGroups { get; protected set; }
public virtual ModuleInfo SelectedModuleInfo { get; set; }
public virtual Type SplashScreenType { get; set; }
public virtual int DefaultBackstatgeIndex { get; set; }
public virtual bool HasPrinting { get; set; }
public virtual bool IsBackstageOpen { get; set; }
[Required]
protected virtual ICurrentWindowService CurrentWindowService { get { return null; } }
public MainWindowViewModel()
{
List modules = new List()
{
ViewModelSource.Create(() => new ModuleInfo("UCMarketA", this, "市场A")).SetIcon("GridContacts"),
ViewModelSource.Create(() => new ModuleInfo("UCMarketB", this, "市场B")).SetIcon("GridTasks"),
};
ModuleGroups = new ModuleGroup[] { new ModuleGroup("市场列表", modules) };
}
public void Exit()
{
CurrentWindowService.Close();
}
public void OnModulesLoaded()
{
if (SelectedModuleInfo == null)
{
SelectedModuleInfo = ModuleGroups.First().ModuleInfos.First();
SelectedModuleInfo.IsSelected = true;
SelectedModuleInfo.Show();
}
}
}
//为NavBarControl构造数据源的类
public class ModuleGroup
{
public ModuleGroup(string _title, IEnumerable _moduleInfos)
{
Title = _title;
ModuleInfos = _moduleInfos;
}
public string Title { get; private set; }
public IEnumerable ModuleInfos { get; private set; }
}
//一个NavBarItem对应一个ModuleInfo
public class ModuleInfo
{
ISupportServices Parent;
public ModuleInfo(string _type, object parent, string _title)
{
Type = _type;
this.Parent = (ISupportServices)parent;
Title = _title;
}
public string Type { get; private set; }
public virtual bool IsSelected { get; set; }
public string Title { get; private set; }
public virtual Uri Icon { get; set; }
public ModuleInfo SetIcon(string icon)
{
this.Icon = AssemblyHelper.GetResourceUri(typeof(ModuleInfo).Assembly, string.Format("Images/{0}.png", icon));
return this;
}
//选中按钮时触发导航事件,至于为什么,为了极大程度上的符合MVVM,这是我暂时能想到的解决问题的唯一办法。
public void Show(object parameter = null)
{
INavigationService navigationService = Parent.ServiceContainer.GetService();
navigationService.Navigate(Type, Type, Parent);
}
}
}
子界面,以B为例。
MarketB.xaml,子界面中有不同的菜单,所以需要在子界面写B的菜单RibbonControl.
DockPanel.Dock="Top" RibbonStyle="Office2010">
MarketB.cs
namespace WPFOptimizeTry
{
///
/// UCMarketB.xaml 的交互逻辑
///
public partial class UCMarketB : UserControl
{
public UCMarketB()
{
InitializeComponent();
}
}
}
UCMarketBViewModel.cs
namespace WPFOptimizeTry
{
public class UCMarketBViewModel
{
public virtual string BindMarketBContent { get; set; }
public UCMarketBViewModel()
{
}
public void DealShow( )
{
BindMarketBContent = "成交行情B";
}
public void QuotationlShow()
{
BindMarketBContent = "行情显示";
}
public void QuotationDeal()
{
BindMarketBContent = "成交";
}
}
}
综上,其实并不复杂,主要是写好各个界面、控件的布局,然后就是想好如何Show出界面。
由于刚刚学习,如有我哪里有不对或者你有更好的建议,欢迎讨论。