原文:C# WPF 左侧菜单右侧内容布局效果实现

我们要做的效果是这样的,左侧是可折叠的菜单栏,右侧是内容区域,点击左侧的菜单项右侧内容区域则相应地切换。

wpf实现的话,我的办法是用一个tabcontrol,修改tabcontrol的样式模板,首先将控件的TabStripPlacement设置为left使tabcontrol的item header部分靠左内容靠右,然后用一个Expander将TabPanel包住实现可折叠菜单效果,最后就是把用到的控件样式修改一下即可。

先看下效果图:

WPF做出来的效果图:

未完善的问题:

不能添加多个可折叠菜单,我暂时没想到比较好的办法。

新建一个项目,名字随你,新建一个自定义用户控件前台修改为:

<TabControl x:Class="cloundmusic_left.controls.itabcontrol"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:cloundmusic_left.controls"
mc:Ignorable="d"
d:DesignHeight="" d:DesignWidth="">
<TabControl.Resources>
<!--折叠菜单的箭头按钮-->
<ControlTemplate x:Key="ExpanderToggleButton"
TargetType="{x:Type ToggleButton}">
<Border Background="{TemplateBinding Background}" Width="{TemplateBinding Width}" x:Name="Border"
> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CheckStates">
<VisualState x:Name="Checked">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)"
Storyboard.TargetName="CollapsedArrow">
<DiscreteObjectKeyFrame KeyTime=""
Value="{x:Static Visibility.Hidden}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)"
Storyboard.TargetName="ExpandededArrow">
<DiscreteObjectKeyFrame KeyTime=""
Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Unchecked" />
<VisualState x:Name="Indeterminate" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid Margin="0,0,13,0" HorizontalAlignment="Right" VerticalAlignment="Center">
<Path x:Name="CollapsedArrow"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 0 0 L 4 4 L 8 0 Z">
<Path.Fill>
<SolidColorBrush Color="#7d7d7d" />
</Path.Fill>
</Path>
<Path x:Name="ExpandededArrow"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="Collapsed"
Data="M 0 4 L 4 0 L 8 4 Z">
<Path.Fill>
<SolidColorBrush Color="#7d7d7d" />
</Path.Fill>
</Path>
</Grid>
</Border>
</ControlTemplate> <Style TargetType="{x:Type Expander}">
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Foreground" Value="#7d7d7d"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Expander}">
<Border BorderBrush="#e1e1e2" BorderThickness="0,0,1,0">
<Grid Background="#f5f5f7">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition x:Name="ContentRow"
Height="" />
</Grid.RowDefinitions> <Border MinHeight="" x:Name="Border"
Grid.Row=""
> <Grid VerticalAlignment="Center"> <ContentPresenter
Margin="" ContentSource="Header"
RecognizesAccessKey="True" /> <ToggleButton Background="Transparent" Width="{Binding ElementName=Border,Path=ActualWidth}" Panel.ZIndex="" OverridesDefaultStyle="True"
Template="{StaticResource ExpanderToggleButton}"
IsChecked="{Binding IsExpanded, Mode=TwoWay,
RelativeSource={RelativeSource TemplatedParent}}"> </ToggleButton>
</Grid>
</Border>
<Border x:Name="Content"
Grid.Row=""
> <ContentPresenter/>
</Border>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded"
Value="True">
<Setter TargetName="ContentRow"
Property="Height"
Value="{Binding DesiredHeight, ElementName=Content}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <Style TargetType="{x:Type TabItem}">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid SnapsToDevicePixels="true">
<Border Cursor="Hand" MinWidth="" MinHeight="" x:Name="Bd" CornerRadius="" Background="Transparent" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="3,0,0,0" Padding="" Margin="">
<Grid VerticalAlignment="Center" HorizontalAlignment="Left">
<StackPanel Orientation="Horizontal"> <ContentPresenter x:Name="Content" Margin="17,0,0,0" ContentSource="Header" HorizontalAlignment="Left" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/> </StackPanel> </Grid>
</Border>
</Grid> <ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="false"> <Setter Property="Foreground" Value="#5c5c5c"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true"> <Setter Property="Foreground" Value="#000000"/>
</Trigger> <Trigger Property="IsSelected" Value="true">
<Setter Property="Panel.ZIndex" Value=""/>
<Setter Property="Background" TargetName="Bd" Value="#e6e7ea"/> <Setter Property="Foreground" Value="#000000"/>
<Setter Property="BorderThickness" TargetName="Bd" Value="3,0,0,0"/>
<Setter Property="BorderBrush" TargetName="Bd" Value="#c62f2f"/> </Trigger> </ControlTemplate.Triggers>
</ControlTemplate> </Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
<TabControl.Style>
<Style TargetType="{x:Type TabControl}">
<Setter Property="OverridesDefaultStyle"
Value="True" />
<Setter Property="TabStripPlacement"
Value="Left" />
<Setter Property="SnapsToDevicePixels"
Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:itabcontrol}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> <!--可折叠菜单-->
<Expander Header="{TemplateBinding iTitle}" Grid.Column="">
<!--菜单项-->
<TabPanel x:Name="HeaderPanel" IsItemsHost="True"
KeyboardNavigation.TabIndex=""
Background="Transparent" />
</Expander>
<!--右侧内容区域-->
<Border x:Name="Border"
Grid.Column="" KeyboardNavigation.TabNavigation="Local"
KeyboardNavigation.DirectionalNavigation="Contained"
KeyboardNavigation.TabIndex=""> <ContentPresenter x:Name="PART_SelectedContentHost"
Margin=""
ContentSource="SelectedContent" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> </TabControl.Style>
</TabControl>

修改后你的vs也许会抱一个错:

这个报错就像vs错误列表里的警告一样,没啥卵用,不用理它,程序是可以运行的

ok继续,后台代码加一个依赖属性:

 public string iTitle
{
get { return (string)GetValue(iTitleProperty); }
set { SetValue(iTitleProperty, value); }
} public static readonly DependencyProperty iTitleProperty =
DependencyProperty.Register("iTitle", typeof(string), typeof(itabcontrol));

然后只要在界面中使用这个控件即可。

呃我发现这个项目并没有什么难点,实现方法开头也说了,所以这里不一步步讲了。

值得一提的是,加入的Expander也就是可折叠菜单的header代表菜单名,这里我是把修改的这个TabControl写在一个自定义控件里的,在界面调用的时候默认是无法给它设置内容的,所以我们要在这个自定义控件中加入一个依赖属性,然后在样式中绑定这个属性。这里就涉及到一个比较有意思的东西,在样式中绑定一个属性也许你没接触过,但是你一定知道Binding的用法,而在样式中是没办法这么用的,那该怎么去做呢?相信你看完代码就知道了。

项目下载:

点我下载

C# WPF 左侧菜单右侧内容布局效果实现的更多相关文章

  1. 左侧菜单栏右侧内容(改进,有js效果)

    (如有错敬请指点,以下是我工作中遇到并且解决的问题)上一篇文章是简洁版 这是上一篇文章的改进. 上一篇文章的左侧菜单是没有子目录的. 这是效果图: 左侧菜单代码: <div class=&quo ...

  2. HTMLCSS实现左侧固定宽度右侧内容可滚动

    在做移动端页面的时候,经常会碰到一个div中分左右两个div,左侧div固定宽度或百分比,右侧div中内容左右溢出,需要左右滑动才可以浏览到全部内容,为此写了一个demo. 处理这个问题的核心关键点是 ...

  3. HTML和CSS实现左侧固定宽度右侧内容可滚动

    在做移动端页面的时候,经常会碰到一个div中分左右两个div,左侧div固定宽度或百分比,右侧div中内容左右溢出,需要左右滑动才可以浏览到全部内容,为此写了一个demo. 处理这个问题的核心关键点是 ...

  4. C# 窗体 类似framest 左侧点击右侧显示 左侧菜单右侧显示

    首先托一个splitContainer调节大小位置 然后进行再新创建一个窗体名为add 在左侧拖入button按钮 进入代码阶段 更改属性 public Main() { InitializeComp ...

  5. css布局之左侧固定右侧自适应布局

    参考代码如下: <form id="form1" style="height:100%; overflow:hidden;"> <div st ...

  6. bootstrap实现左侧图片右侧文字布局

    效果图 代码 通过class="media-left"来控制相对位置 <!DOCTYPE html> <html> <head lang=" ...

  7. ifram 实现左侧菜单,右侧显示内容

    一般都是左侧的导航栏中的a标签中写一个target(a标签有target属性), 右侧的div标签中写一个iframe,在iframe中有name的属性,在左侧a标签中的target写上iframe中 ...

  8. ionic js 侧栏菜单 把主要内容区域从一边拖动到另一边,来让左侧或右侧的侧栏菜单进行切换

    ionic 侧栏菜单 一个容器元素包含侧边菜单和主要内容.通过把主要内容区域从一边拖动到另一边,来让左侧或右侧的侧栏菜单进行切换. 效果图如下所示: 用法 要使用侧栏菜单,添加一个父元素<ion ...

  9. ajax实现简单的点击左侧菜单,右侧加载不同网页

    实现:ajax实现点击左侧菜单,右侧加载不同网页(在整个页面无刷新的情况下实现右侧局部刷新,用到ajax注意需要在服务器环境下运行,从HBuilder自带的服务器中打开浏览效果即可) 原理:ajax的 ...

随机推荐

  1. C#无符号右移

    /// <summary>         /// 无符号右移,与JS中的>>>等价         /// </summary>         /// & ...

  2. [内核编程] Windebug双机调试环境搭建

    Windebug双机调试环境搭建    开始进行内核编程/驱动编程的调试工作是非常烦人的,由于程序运行与内核层不受操作系统的管控,所以容易引起主机蓝屏和崩溃是常有的事.这也就使得内核程序的调试成了一大 ...

  3. Android多线程研究(8)——Java5中Futrue获取线程返回结果

    我们先来看一下ExecutorService中的执行方法: 在上一篇中我们使用了execute方法启动线程池中的线程执行,这一篇我们来看看submit方法的使用:submit提交一个返回值的任务用于执 ...

  4. http500:服务器内部错误案例详解(服务器代码语法错误或者逻辑错误)

    http500:服务器内部错误案例详解(服务器代码语法错误或者逻辑错误) 一.总结 服务器内部错误可能是服务器中代码运行的时候的语法错误或者逻辑错误 二.http500:服务器内部错误案例详解 只是一 ...

  5. ### Hibernate中的事务与并发 ###

    **事务相关的概念** 1. 什么是事务 * 事务就是逻辑上的一组操作,组成事务的各个执行单元,操作要么全都成功,要么全都失败. * 转账的例子:冠希给美美转钱,扣钱,加钱.两个操作组成了一个事情! ...

  6. 一起学Python:tcp服务器

    tcp服务器 生活中的电话机 如果想让别人能更够打通咱们的电话获取相应服务的话,需要做以下几件事情: 买个手机 插上手机卡 设计手机为正常接听状态(即能够响铃) 静静的等着别人拨打 tcp服务器 如同 ...

  7. Android系统编译环境初始化时Product产品的import-nodes过程

    从运行make -f config,mk文件開始,config,mk作为当前的makefile文件.将会被make解析,一般make解析Makefile文件流程首先是载入当中include的各种其它m ...

  8. Effective C++ 条款14

    在资源管理器中小心copying行为 上节是对资源的管理说明.有时候我们不能依赖于shared_ptr或者auto_ptr,所以我们须要自己建立一个资源管理类来管理自己的资源. 比如建立一个类来管理M ...

  9. [React] displayName for stateless component

    We can use 'displayName' on component to change its component tag in dev tool: import React from 're ...

  10. 自己动手编写一个VS插件(八)

    作者:朱金灿 来源:http://blog.csdn.net/clever101 利用业余时间继续开发一个VS插件.我要开发的插件是一个代码库插件,主要是用于积累我平时要使用的代码.在之前我已经实现了 ...