WPF仿Word头部格式,涉及DEV RibbonControl,NarvbarControl,ContentPresenter,Navigation

时间:2023-03-08 22:07:17

时隔1个月,2015/06/17走进新的环境。

最近一个星期在学习仿Word菜单栏的WPF实现方式,废话不多说,先看一下效果。

WPF仿Word头部格式,涉及DEV RibbonControl,NarvbarControl,ContentPresenter,Navigation

打开界面后,默认选中【市场A】,A对应的菜单栏,如上图,

选择【市场B】后讲改变菜单栏,和B相应的界面。

WPF仿Word头部格式,涉及DEV RibbonControl,NarvbarControl,ContentPresenter,Navigation

要实现上述的功能,要怎么解决?

实际上,每个界面都可以看成有三部分组成,顶部的DEV.RibbonControl,左侧的DEV.NavbarControl,和中间显示主要界面C部分。

NavBarControl中包含多个NavBarItem,当切换NavBarItem时,就加载相应的子界面到C处。但,除了MainWindow完整包含这几个部分外,其他子界面都不一定。

WPF仿Word头部格式,涉及DEV RibbonControl,NarvbarControl,ContentPresenter,Navigation

下面,就围绕这3个部分展开。

1、MainWindow.xaml

<dxr:DXRibbonWindow  x:Class="WPFOptimizeTry.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
xmlns:dxb="http://schemas.devexpress.com/winfx/2008/xaml/bars"
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
xmlns:dxdo="http://schemas.devexpress.com/winfx/2008/xaml/docking"
xmlns:dxn="http://schemas.devexpress.com/winfx/2008/xaml/navbar"
xmlns:dxr="http://schemas.devexpress.com/winfx/2008/xaml/ribbon"
xmlns:dxrt="http://schemas.devexpress.com/winfx/2008/xaml/ribbon/themekeys"
xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm"
xmlns:dxwui="http://schemas.devexpress.com/winfx/2008/xaml/windowsui"
xmlns:dxwuin="http://schemas.devexpress.com/winfx/2008/xaml/windowsui/navigation"
xmlns:dxnt="http://schemas.devexpress.com/winfx/2008/xaml/navbar/themekeys"
xmlns:local="clr-namespace:WPFOptimizeTry"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="优化尝试用例"
Height="900" Width="1300"
WindowStartupLocation="CenterScreen"
UseLayoutRounding="True"
DataContext="{dxmvvm:ViewModelSource Type=local:MainWindowViewModel}"
Icon="pack://application:,,,/WPFOptimizeTry;component/demoicon.ico" > <dxmvvm:Interaction.Behaviors>
<dxmvvm:CurrentWindowService />
<dx:DialogService/>
</dxmvvm:Interaction.Behaviors>
<dxb:BarManager Name="barManager">
<dxb:BarManager.Items>
<dxr:RibbonGalleryBarItem x:Name="ribbonGalleryBarItem1">
<dxmvvm:Interaction.Behaviors>
<dxr:RibbonGalleryItemThemeSelectorBehavior/>
</dxmvvm:Interaction.Behaviors>
<dxr:RibbonGalleryBarItem.Gallery>
<dxb:Gallery ItemGlyphSize="30,24" HoverGlyphSize="48,48"/>
</dxr:RibbonGalleryBarItem.Gallery>
</dxr:RibbonGalleryBarItem>
<dxb:BarCheckItem x:Name="layoutNormal" IsChecked="{Binding IsExpanded, ElementName=navPanelView, Mode=TwoWay}"
Glyph="pack://application:,,,/WPFOptimizeTry;component/Images/normal.png" GlyphSize="Small"/>
<dxb:BarCheckItem x:Name="layoutReading"
IsChecked="{Binding IsExpanded, ElementName=navPanelView, Mode=TwoWay, Converter={StaticResource BooleanNegationConverter}}"
Glyph="pack://application:,,,/WPFOptimizeTry;component/Images/reading.png" GlyphSize="Small"/> </dxb:BarManager.Items>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<dxr:RibbonControl RibbonStyle="Office2010" x:Name="ribbon" AllowCustomization="False">
<!--ApplicationMenu可以先忽略-->
<dxr:RibbonControl.ApplicationMenu>
<dxr:BackstageViewControl SelectedTabIndex="{Binding DefaultBackstatgeIndex, Mode=TwoWay}"
IsOpen="{Binding IsBackstageOpen, Mode=TwoWay}">
<dxr:BackstageViewControl.Items>
<dxr:BackstageTabItem Content="个人账户" >
</dxr:BackstageTabItem>
<dxr:BackstageTabItem Content="订单查询" IsEnabled="{Binding HasPrinting, Mode=OneWay}">
</dxr:BackstageTabItem>
<dxr:BackstageButtonItem Content="授信查询" Command="{Binding ExitCommand}" />
</dxr:BackstageViewControl.Items>
</dxr:BackstageViewControl>
</dxr:RibbonControl.ApplicationMenu>
<!--RibbonDefaultPageCategory 主界面默认显示的菜单,像Word里面可能先默认显示-->
<dxr:RibbonDefaultPageCategory>
<dxr:RibbonPage Caption="主页" >
<dxr:RibbonPageGroup Caption="个人账户" ShowCaptionButton="False">
<dxb:BarButtonItem Content="修改" x:Name="btnModify" RibbonStyle="Large"
Glyph="pack://application:,,,/WPFOptimizeTry;component/Images/WordProcessing.png"
Command="{Binding ModifyCommand}" ></dxb:BarButtonItem>
</dxr:RibbonPageGroup>
<dxr:RibbonPageGroup Caption="XXXX" ShowCaptionButton="False">
<dxb:BarButtonItem Content="MMM" x:Name="btnM" RibbonStyle="Large"
Glyph="pack://application:,,,/WPFOptimizeTry;component/Images/WordProcessing.png"
Command="{Binding MoCommand}" ></dxb:BarButtonItem>
</dxr:RibbonPageGroup>
</dxr:RibbonPage>
</dxr:RibbonDefaultPageCategory>
</dxr:RibbonControl> <dxdo:DockLayoutManager Grid.Row="1" Margin="6">
<dxdo:LayoutGroup Caption="LayoutRoot">
<dxdo:LayoutPanel Caption="WPF Products" ItemWidth="Auto" AllowClose="False" ShowCaption="False" MaxWidth="183" Name="layoutPanel" AllowSizing="{Binding IsExpanded, ElementName=navPanelView}">
<dxn:NavBarControl SelectedItem="{Binding SelectedModuleInfo, Mode=TwoWay}" ItemsSource="{Binding Path=ModuleGroups}">
<dxmvvm:Interaction.Triggers>
<dxmvvm:EventToCommand EventName="Loaded" Command="{Binding OnModulesLoadedCommand}" />
</dxmvvm:Interaction.Triggers>
<dxn:NavBarControl.ItemStyle>
<Style TargetType="dxn:NavBarGroup">
<Setter Property="Header" Value="{Binding Path=Title}" />
<Setter Property="ItemsSource" Value="{Binding Path=ModuleInfos}" />
<Setter Property="ItemStyle">
<Setter.Value>
<Style TargetType="dxn:NavBarItem">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Setter Property="Content" Value="{Binding Path=Title}" />
<Setter Property="ImageSource" Value="{Binding Path=Icon}" />
<Setter Property="Command" Value="{Binding Path=ShowCommand}" />
<Setter Property="ImageSettings">
<Setter.Value>
<dxn:ImageSettings Width="32" Height="32" Stretch="Uniform" StretchDirection="Both" />
</Setter.Value>
</Setter>
<Setter Property="LayoutSettings">
<Setter.Value>
<dxn:LayoutSettings ImageDocking="Top" ImageHorizontalAlignment="Center" TextHorizontalAlignment="Center" ImageVerticalAlignment="Center" TextVerticalAlignment="Center" />
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
</dxn:NavBarControl.ItemStyle>
<dxn:NavBarControl.View>
<dxn:NavigationPaneView x:Name="navPanelView" IsOverflowPanelVisible="False" IsSplitterVisible="False" />
</dxn:NavBarControl.View>
</dxn:NavBarControl>
</dxdo:LayoutPanel>
<dxdo:LayoutPanel AllowClose="False" AllowFloat="False" AllowHide="False" ShowCaption="False" ShowBorder="False" ShowCloseButton="False">
<dxwui:NavigationFrame x:Name="documentFrame" Navigating="OnDocumentFrameNavigating">
<dxwui:NavigationFrame.Resources>
<Style TargetType="dxwui:PageAdornerControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="dxwui:PageAdornerControl">
<ContentPresenter Content="{TemplateBinding Content}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</dxwui:NavigationFrame.Resources>
<dxmvvm:Interaction.Behaviors>
<dxwuin:FrameNavigationService Frame="{Binding ElementName=documentFrame}" />
<dx:DXSplashScreenService SplashScreenType="{Binding SplashScreenType}" />
</dxmvvm:Interaction.Behaviors>
</dxwui:NavigationFrame>
</dxdo:LayoutPanel>
</dxdo:LayoutGroup>
</dxdo:DockLayoutManager> <dxr:RibbonStatusBarControl x:Name="statusBar" Grid.Row="2">
<dxr:RibbonStatusBarControl.RightItemLinks>
<dxb:BarCheckItemLink BarItemName="layoutNormal"/>
<dxb:BarCheckItemLink BarItemName="layoutReading"/>
</dxr:RibbonStatusBarControl.RightItemLinks>
</dxr:RibbonStatusBarControl>
</Grid>
</dxb:BarManager> </dxr:DXRibbonWindow>

MainWindow.cs

namespace WPFOptimizeTry
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
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<ModuleGroup> 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<ModuleInfo> modules = new List<ModuleInfo>()
{
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<ModuleInfo> _moduleInfos)
{
Title = _title;
ModuleInfos = _moduleInfos;
}
public string Title { get; private set; }
public IEnumerable<ModuleInfo> 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<INavigationService>();
navigationService.Navigate(Type, Type, Parent);
}
}
}

子界面,以B为例。

MarketB.xaml,子界面中有不同的菜单,所以需要在子界面写B的菜单RibbonControl.

<UserControl x:Class="WPFOptimizeTry.UCMarketB"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
xmlns:dxb="http://schemas.devexpress.com/winfx/2008/xaml/bars"
xmlns:dxr="http://schemas.devexpress.com/winfx/2008/xaml/ribbon"
xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol"
xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
xmlns:dxdo="http://schemas.devexpress.com/winfx/2008/xaml/docking"
xmlns:local="clr-namespace:WPFOptimizeTry"
DataContext="{dxmvvm:ViewModelSource Type=local:UCMarketBViewModel}"
Height="300" Width="300">
<UserControl.Resources>
<ResourceDictionary> <!--<local:ItemTypeToBooleanConverter x:Key="itemTypeToBooleanConverter"/>--> <Style x:Key="gridControlMVVMStyle" TargetType="{x:Type dxg:GridControl}">
<Setter Property="ItemsSource" Value="{Binding ItemsSource}"/>
<Setter Property="ColumnsSource" Value="{Binding Columns}"/>
<Setter Property="AutoExpandAllGroups" Value="True"/>
<Setter Property="SelectedItem" Value="{Binding SelectedItem, Mode=TwoWay}"/>
<Setter Property="FilterString" Value="{Binding FilterString, Mode=TwoWay}"/>
</Style>
<dxg:GridControl x:Key="printGridControl" >
<dxg:GridControl.View>
<dxg:TableView AutoWidth="True"/>
</dxg:GridControl.View>
<dxg:GridControl.GroupSummary>
<dxg:GridSummaryItem SummaryType="Count"/>
</dxg:GridControl.GroupSummary>
</dxg:GridControl>
</ResourceDictionary>
</UserControl.Resources>
<dxmvvm:Interaction.Behaviors>
<dxmvvm:NotificationService UseWin8NotificationsIfAvailable="False"
PredefinedNotificationTemplate="ShortHeaderAndLongText"/>
</dxmvvm:Interaction.Behaviors>
<Grid>
<dxb:BarManager CreateStandardLayout="False">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<dxr:RibbonControl DockPanel.Dock="Top" RibbonStyle="Office2010">
<dxr:RibbonDefaultPageCategory>
<dxr:RibbonPage Caption="B市场行情" MergeOrder="1">
<dxr:RibbonPageGroup Caption="报价行情">
<dxb:BarButtonItem Content="行情显示" x:Name="btnQuotationlShow" RibbonStyle="Large"
Glyph="pack://application:,,,/WPFOptimizeTry;component/Images/Analytics.png"
Command="{Binding QuotationlShowCommand}"></dxb:BarButtonItem>
<dxb:BarButtonItem Content="报价成交" x:Name="btnQuotationDeal" RibbonStyle="Large"
Glyph="pack://application:,,,/WPFOptimizeTry;component/Images/Tasks/Completed_32x32.png"
Command="{Binding QuotationDealCommand}" ></dxb:BarButtonItem>
</dxr:RibbonPageGroup>
<dxr:RibbonPageGroup Caption="成交行情">
<dxb:BarButtonItem Content="成交行情" x:Name="btnDealShow" RibbonStyle="Large"
Glyph="pack://application:,,,/WPFOptimizeTry;component/Images/WeatherMap.png"
Command="{Binding Path=DealShowCommand}"></dxb:BarButtonItem>
</dxr:RibbonPageGroup>
</dxr:RibbonPage>
</dxr:RibbonDefaultPageCategory>
<dxr:RibbonPageCategory>
<dxr:RibbonPage Caption="风控信息查询">
<dxr:RibbonPageGroup Caption="授信查询"></dxr:RibbonPageGroup>
</dxr:RibbonPage>
</dxr:RibbonPageCategory>
</dxr:RibbonControl>
<dxlc:LayoutControl Margin="0" Padding="0" Grid.Row="1">
<Grid Background="Pink" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock x:Name="blkB" Text="{Binding Path=BindMarketBContent,Mode=TwoWay}" Grid.Row="1" TextWrapping="Wrap" Foreground="Red" FontSize="36" />
</Grid>
</dxlc:LayoutControl >
<dxr:RibbonStatusBarControl>
<dxr:RibbonStatusBarControl.LeftItemLinks>
<dxb:BarStaticItemLink BarItemName="summaryCount"/>
<dxb:BarItemLinkSeparator/>
<dxb:BarButtonItemLink BarItemName="reminders"/>
</dxr:RibbonStatusBarControl.LeftItemLinks>
</dxr:RibbonStatusBarControl>
</Grid>
</dxb:BarManager>
</Grid>
</UserControl>

MarketB.cs

namespace WPFOptimizeTry
{
/// <summary>
/// UCMarketB.xaml 的交互逻辑
/// </summary>
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出界面。

由于刚刚学习,如有我哪里有不对或者你有更好的建议,欢迎讨论。