WPF自学手册-读书笔记(三)小有所成

应用程序窗口

WPF应用程序的重要两个类型是Application 和 Window,前者在一个应用程序中是全局唯一的,代表一个应用程序,它可以提供很多基础的应用程序的服务,应用程序也有生命周期。
应用程序的启动一般情况下是通过用户双击应用程序,由操作系统启动应用程序,当运行了Run函数之后,应用程序会触发一个Startup事件,它会一直监听鼠标,键盘或者手写笔的输入。应用程序有两种状态,一种是激活(Activated)状态,另一种是非激活(Deactiveated)状态。正常情况下,应用程序是通过用户关闭而退出的,但也会出现各种异常的情况,导致应用程序退出。WPF提供一种捕捉异常的机制,因此当异常出现的时候。可以选择继续或者退出。
在这里插入图片描述

应用程序

应用程序入口

应用程序的入口都是Main函数,其中两种主要类型是Application和window。 前者在一个程序中是全局唯一的,可以通过Application.Current来获得当前的Application对象,第1个创建的窗口对象被认为是主窗口。

在Application调用Run之前,首先创建窗口对象。而且设置了一些必要的属性,也可以在应用程序启动之初做好一个闪屏。实际上如果我们查看WPF自动生成的App.g.i.cs会发现多了两行出现闪屏的代码

/// <summary>
        /// Application Entry Point.
        /// </summary>
        [System.STAThreadAttribute()]
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
        public static void Main() {
            SplashScreen splashScreen = new SplashScreen("startup.jpg");
            splashScreen.Show(true);
            mumu_application.App app = new mumu_application.App();
            app.InitializeComponent();
            app.Run();
        }

应用程序的起点

如前所述,Application调用Run函数应用程序进入消息循环,该循环不断地响应并处理事件。应用程序的第一个事件是Startup事件,这是应用程序的起点,可以在这个事件函数中创建窗口,下列代码。在App.xaml文件中添加一个Startup的事件处理函数。
<Application x:Class="mumu_application.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              Startup="Application_Startup" Activated="Application_Activated" Deactivated="Application_Deactivated" DispatcherUnhandledException="Application_DispatcherUnhandledException">
    <!--StartupUri="MainWindow.xaml"-->
    <Application.Resources>
         
    </Application.Resources>
</Application>
在相应的App.xaml.cs文件中实现该事件处理函数,其中创建主窗口并显示,如下列代码
 /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            MainWindow win = new MainWindow();
            win.Show();
        }
    }
更简单的方法是将窗口的xaml文件赋值给Application对象的StartupUri属性,这也是WPF的默认做法,如下代码
<Application x:Class="WpfApplication1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>

应用程序的两种状态

一种是激活(Activated);一种是非激活(Deactivated)状态。一般来说,在桌面上只有一个窗口处在激活状态,其他窗口都处于非激活状态。激活窗口后可以接受用户的输入,拥有激活窗口的应用程序即激活状态,而其他应用程序则处于非激活状态。
用户可以通过Alt+Tab键来切换应用程序的状态,也可以通过选中应用程序的窗口来激活应用程序。WPF里可以通过检查Activate和Deactivated事件来判断应用程序处于何种状态,如下代码,在App.xaml文件添加这两个事件的处理函数。
<Application x:Class="mumu_application.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              Startup="Application_Startup" Activated="Application_Activated" Deactivated="Application_Deactivated" DispatcherUnhandledException="Application_DispatcherUnhandledException">
    <!--StartupUri="MainWindow.xaml"-->
    <Application.Resources>
         
    </Application.Resources>
</Application>

在相应的App.xaml.cs文件中分别实现这两个事件的处理函数。如下代码

 public partial class App : Application
    {
		private void Application_Activated(object sender, EventArgs e)
        {
            MessageBox.Show("activated");
        }

        private void Application_Deactivated(object sender, EventArgs e)
        {
            MessageBox.Show("deactivated");
        }
    }

应用程序的异常情况

WPF在程序出错时会触发一个DispatcherUnhandledException事件,使程序响应该事件以做出相应的处理。如在窗口中添加两个按钮的Click事件处理函数,在其中有意制造两个错误分别用于抛出异常和显示一个值为NULL的窗口,如下代码

namespace mumu_application
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
           
            throw new DivideByZeroException("Recoverable Exception");
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            Window win = null;
            win.Show();
        }

    }
}

在App.xaml文件中添加处理异常事件响应函数,如下代码

<Application x:Class="mumu_application.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              Startup="Application_Startup" Activated="Application_Activated" Deactivated="Application_Deactivated" DispatcherUnhandledException="Application_DispatcherUnhandledException">
    <!--StartupUri="MainWindow.xaml"-->
    <Application.Resources>
         
    </Application.Resources>
</Application>

同理,仍然在App.xaml.cs中实现该函数,代码实现如下

private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            e.Handled = true;
            if (e.Exception is DivideByZeroException)
            {
                MessageBox.Show("嗨,兄弟你遇到麻烦了!不过还好,程序仍可以恢复运行!");
            }
            else
            {
                MessageBox.Show("嗨,兄弟你遇到大麻烦了!程序马上退出。啊~~~");

                this.Shutdown(-1);
            }
        }

在这里插入图片描述
还有一种非正常的情况,即关机,重启或者注销当前用户时应用程序也会退出。这种情况发生时候应用程序会接收一个SessionEnding事件,该事件的处理函数中的类型为SessionEndingCancelEventArgs的参数e包含Session结束的原因信息。如果用户不希望操作系统关机,重启或者注销的话,还可以将该参数e的Cancel属性设置为true。阻止操作系统关机,重启或注销。

<Application x:Class="mumu_application.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              Startup="Application_Startup" Activated="Application_Activated" Deactivated="Application_Deactivated" DispatcherUnhandledException="Application_DispatcherUnhandledException"
              SessionEnding="Application_SessionEnding">
    <!--StartupUri="MainWindow.xaml"-->
    <Application.Resources>
         
    </Application.Resources>
</Application>
private void Application_SessionEnding(object sender, SessionEndingCancelEventArgs e)
        {
            string msg = string.Format("{0}.End session?", e.ReasonSessionEnding);
            MessageBoxResult result = MessageBox.Show(msg, "Session Ending", MessageBoxButton.YesNo);
            if(result == MessageBoxResult.No)
            {
                e.Cancel = true;
            }
        }

应用程序正常退出

应用程序可以以下3种情况下正常退出,即关闭主窗口,关闭应用程序的所有窗口及显示调用Shutdown函数。这3种情况由Application的ShutdownMode属性决定。该属性的如下3种值分别对应上述3种情况。
(1)OnMainWindowClose:表示只有关闭主窗口时应用程序才会退出。
(2)OnLastWindowClose:表示关闭应用程序的所有窗口时应用程序才会退出。
(3)OnExplicitShutdown:表示显式调用Shutdown函数应用程序才会退出。
Shutdown函数有两种形式:一是不用传入任何参数;二是需要传入一个int类型的值,这个值作为一个退出代码。

窗口

窗口的组成:

在这里插入图片描述- 窗口的生命周期
与窗口有关的事件如下:
(1)SourceInitied: 窗口的第一个事件。
(2)Activated: 一般说来,在默认情况下创建的窗口是激活状态,因此该事件会紧接其后。
(3)Loaded: 表示已经初始化窗口。
(4)ContentRended: 如果一个窗口的Content属性为空或者客户区没有任何内容,不会触发该事件。但是这种情况在实际应用中很少见,因此往往都会触发该事件。
(5)Deactivated: 当窗口处在非激活状态是触发该事件。
(6)Closing:该事件发生在窗口关闭之前,也可以通过处理该事件阻止关闭窗口。
(7)Closed:该事件标识一个窗口生命周期结束。
在这里插入图片描述
- 窗口属性
窗口的属性可以分成位置和尺寸,以及外观和样式两大类。
在这里插入图片描述
在这里插入图片描述
与外观和样式相关的属性
(1)ResizeMode:
NoResize:窗口不能调整其大小,同时没有最小化和最大化。
CanMinimize:窗口可以最小化,但不能最大化,并且不能调整其大小。
CanResize:窗口能调整其大小,并且可以最小化和最大化。
CanResizeWithGrip:与CanResize相似,增加了控制把手。
(2)WindowStyle:
在这里插入图片描述
(3) ShowInTaskbar和Topmost

非规则窗口

实际上非规则的窗口还是一个矩形窗口,只不过其背景设置为透明色
(1)绘制图形
(2)设置窗口背景色为透明色( AllowsTransparency=“True”)另外把窗口样式设为None(WindowStyle=“None” )

<Window x:Class="mumu_nonRectangularwindow.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" SizeToContent="WidthAndHeight"
        Background="Transparent" AllowsTransparency="True" WindowStyle="None" MouseLeftButtonDown="Window_MouseLeftButtonDown">
    <!--窗口的形状都绘制在Canvas面板里面-->
    <Canvas Width="200" Height="200" >
        <!--窗口的轮廓-->
        <Path Stroke="DarkGray" StrokeThickness="2">
            <Path.Fill>
                <LinearGradientBrush StartPoint="0.2,0" EndPoint="0.8,1" >
                    <GradientStop Color="White"  Offset="0"></GradientStop>
                    <GradientStop Color="White"  Offset="0.45"></GradientStop>
                    <GradientStop Color="LightBlue" Offset="0.9"></GradientStop>
                    <GradientStop Color="Gray" Offset="1"></GradientStop>
                </LinearGradientBrush>
            </Path.Fill>
            <Path.Data>
                <PathGeometry>
                    <PathFigure StartPoint="40,20" IsClosed="True">
                        <LineSegment Point="160,20"></LineSegment>
                        <ArcSegment Point="180,40" Size="20,20" SweepDirection="Clockwise"></ArcSegment>
                        <LineSegment Point="180,80"></LineSegment>
                        <ArcSegment Point="160,100" Size="20,20" SweepDirection="Clockwise"></ArcSegment>
                        <LineSegment Point="90,100"></LineSegment>
                        <LineSegment Point="90,150"></LineSegment>
                        <LineSegment Point="60,100"></LineSegment>
                        <LineSegment Point="40,100"></LineSegment>
                        <ArcSegment Point="20,80" Size="20,20" SweepDirection="Clockwise"></ArcSegment>
                        <LineSegment Point="20,40"></LineSegment>
                        <ArcSegment Point="40,20" Size="20,20" SweepDirection="Clockwise"></ArcSegment>
                    </PathFigure>
                </PathGeometry>
            </Path.Data>
        </Path>
        <!--“拖拽我!”的标签-->
        <Label Width="200" Height="120" FontSize="15" HorizontalContentAlignment="Center" VerticalContentAlignment="Center">Drag Me</Label>
        <!--关闭按钮-->
        <Button Canvas.Left="155" Canvas.Top="30" Click="Button_Click">
            <Button.Template>
                <ControlTemplate>
                    <Canvas>
                        <Rectangle Width="15" Height="15" Stroke="Black" RadiusX="3" RadiusY="3">
                            <Rectangle.Fill>
                                <SolidColorBrush x:Name="myAnimatedBrush" Color="Red" />
                            </Rectangle.Fill>
                        </Rectangle>
                        <Line X1="3" Y1="3" X2="12" Y2="12" Stroke="White" StrokeThickness="2"></Line>
                        <Line X1="12" Y1="3" X2="3" Y2="12" Stroke="White" StrokeThickness="2"></Line>
                    </Canvas>
                </ControlTemplate>
            </Button.Template>
        </Button>
    </Canvas>

</Window>

效果
在这里插入图片描述

页面和导航

在传统的程序中,同样是两类应用程序模式:一个桌面程序,由窗口和对话框组成;二是Web程序,由多个页面组成,页面之间用超链接连接,并在IE浏览器中运行。WPF导航应用程序从行为上来看,更像一个Web程序。通过超链接来改变窗口或者窗口的部分内容,但其本质仍然是一个桌面程序。
WPF导航应用程序也表现为两种形式:一是将导航内容寄宿于窗口中,二是XAML浏览器应用程序,扩展名“.xbap”.

布局

布局本身

在这里插入图片描述
WPF 包括若干布局控件:
Canvas:子控件提供其自己的布局。
DockPanel:子控件与面板的边缘对齐。
Grid:子控件由行和列定位。
StackPanel:子控件垂直或水平堆叠。
VirtualizingStackPanel:子控件在水平或垂直的行上虚拟化并排列。
WrapPanel:子控件按从左到右的顺序定位,在当前行上的控件超出允许的空间时,换行到下一行。

Canvas

Canvas用4个附加属性Left,Top,Right和Bottom来定位子元素的

<Page x:Class="mumu_layout.Page1"
      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" 
      mc:Ignorable="d" 
      d:DesignHeight="308" d:DesignWidth="294"
	Title="第一片桃林仿真by木木">
    <Border BorderThickness = "2" BorderBrush = "Black" Margin = "5">
        <Canvas>
            <Button Canvas.Left = "24" Canvas.Top = "50" Background="#00000000" 
			Content = "Left=24,Top=50"/>
            <Button  Canvas.Right="24" Canvas.Bottom="50" Background ="#FFFFCCFF" 
			Content = "Right=24,Bottom=50"/>
        </Canvas>
    </Border>
</Page>

效果:
在这里插入图片描述

StackPanel

StackPanel 用于顺序垂直或者水平的排列子元素。它通过Orientation属性控制水平(Horizontal)和垂直(Vertical)排列,默认值是纵向。

<Page x:Class="mumu_layout.Page2"
      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" 
      mc:Ignorable="d" 
      d:DesignHeight="308" d:DesignWidth="251"
	Title="第二片桃林仿真by木木" >
    <Border BorderThickness = "2" BorderBrush = "Black" Margin = "5">
        <StackPanel Orientation="Horizontal" FlowDirection = "RightToLeft">
            <Button Background="#00000000"  MinHeight="50" MinWidth="50" Content = "1"/>
            <Button Background ="#FFFFCCFF" MinHeight="50" MinWidth="50" Content = "2"/>
            <Button Background ="#FFFF9BFF" MinHeight="50" MinWidth="50" Content = "3"/>
            <Button Background ="#FFFF00FF" MinHeight="50" MinWidth="50" Content = "4"/>
        </StackPanel>
    </Border>
</Page>

效果
在这里插入图片描述

WrapPanel

WrapPanel与StackPanel类似,与StackPanel不同的是除了会自动垂直和水平排列子元素以外,当没有空间放置子元素时会自动将其放置在下一行或者下一列中,他特别适用子元素个数不确定的情况。
在这里插入图片描述

<Page x:Class="mumu_layout.Page3"
      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" 
      mc:Ignorable="d" 
      d:DesignHeight="233" d:DesignWidth="251"
	Title="第三片桃林仿真by木木">
    <Border BorderThickness = "2" BorderBrush = "Black" Margin = "5">
        <WrapPanel ItemWidth = "120">
            <Button Background="#00000000"  MinWidth = "50"  Content = "1"/>
            <Button Background ="#FFFFCCFF" MinWidth = "50"  Content = "2"/>
            <Button Background ="#FFFF9BFF" MinWidth = "50"  Content = "3"/>
            <Button Background ="#FFFF00FF" MinWidth = "150"  Content = "4 MinWidth = 150"/>
         </WrapPanel>
    </Border>
</Page>

第四按钮由于长度超出WrapPanel指定的范围,因此被截断。而且随着窗口的大小改变,子元素会自动变换其位置。
效果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

DockPanel

DockPanel可以使子元素停靠在面板的某一条边上,然后拉伸元素以填满全部宽度或者高度,它有一个Dock附加属性,子元素用4个值来控制器停靠,即Left(默认),Top,Right和Bottom。注意Dock并没有Fill值,默认情况下最后一个添加到DockPanel的子元素将填满所有剩余空间;除非DockPanel的LastChidFill属性设置为false.

<Page x:Class="mumu_layout.Page4"
      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" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"
	Title="Page4">
    <Border BorderThickness = "2" BorderBrush = "Black" Margin = "5">
        <!--两种不同属性值的设置,LastChildFill默认为true-->
        <!--<DockPanelLastChildFill = "false">-->
        <DockPanel>
            <Button Background="#00000000"  DockPanel.Dock = "Left"  Content = "1"/>
            <Button Background ="#FFFFCCFF" DockPanel.Dock = "Top"  Content = "2"/>
            <Button Background ="#FFFF9BFF" DockPanel.Dock = "Right"  Content = "3"/>
            <Button Background ="#FFFF00FF" DockPanel.Dock = "Bottom"  Content = "4 "/>
            <Button Background="#00000000"  DockPanel.Dock = "Left"  Content = "5"/>
            <Button Background ="#FFFFCCFF" DockPanel.Dock = "Top"  Content = "6"/>
            <Button Background ="#FFFF9BFF" DockPanel.Dock = "Right"  Content = "7"/>
            <Button Background ="#FFFF00FF" DockPanel.Dock = "Bottom"  Content = "8 "/>
        </DockPanel>
    </Border>
</Page>

效果

在这里插入图片描述
用DcokPanel模拟StackPanel

<Page x:Class="mumu_layout.Page5"
      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" 
      mc:Ignorable="d" 
      d:DesignHeight="281" d:DesignWidth="267"
	Title="第四片桃树林by木木DockPanel模拟StackPanel">
    <Border BorderThickness = "2" BorderBrush = "Black" Margin = "5">
        <DockPanel>
            <Button Background="#00000000"  DockPanel.Dock = "Top"  Content = "1"/>
            <Button Background ="#FFFFCCFF" DockPanel.Dock = "Top"  Content = "2"/>
            <Button Background ="#FFFF9BFF" DockPanel.Dock = "Top"  Content = "3"/>
            <Button Background ="#FFFF00FF" DockPanel.Dock = "Top"  Content = "4 "/>
        </DockPanel>
    </Border>
</Page>

效果
在这里插入图片描述

Grid

Grid是WPF中常用且功能最为强大的布局,允许在一个多行多列的表里排列子元素。
在这里插入图片描述
Grid的行和列有如下3个单位
(1) 绝对尺寸(Absolute):
(2) 自动尺寸(Autosizing):
(3)比例尺寸(Proportional sizing)或者称为“星型尺寸”(Star sizing):

星型尺寸的代码

<Page x:Class="mumu_layout.Page6"
      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" 
      mc:Ignorable="d" 
      d:DesignHeight="564" d:DesignWidth="406"
	Title="星号尺寸Demoby老顽童">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid Grid.Row = "0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width = "100"/>
                <ColumnDefinition Width = "*"/>
            </Grid.ColumnDefinitions>
            <Button Background="#00000000" Grid.Column = "0"  Content = "Width = 100"/>
            <Button Background ="#FFFFCCFF" Grid.Column = "1"  Content = "Width = *"/>
        </Grid>
        <Grid Grid.Row = "1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width = "100"/>
                <ColumnDefinition Width = "*"/>
                <ColumnDefinition Width = "*"/>
                <ColumnDefinition Width = "*"/>
            </Grid.ColumnDefinitions>
            <Button Background="#00000000" Grid.Column = "0"  Content = "Width = 100"/>
            <Button Background ="#FFFFCCFF" Grid.Column = "1"  Content = "Width = *"/>
            <Button Background ="#FFFF9BFF" Grid.Column = "2"  Content = "Width = *"/>
            <Button Background ="#FFFF00FF" Grid.Column = "3"  Content = "Width = *"/>
        </Grid>
        <Grid Grid.Row = "2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width = "100"/>
                <ColumnDefinition Width = "*"/>
                <ColumnDefinition Width = "2*"/>
                <ColumnDefinition Width = "*"/>
            </Grid.ColumnDefinitions>
            <Button Background="#00000000" Grid.Column = "0"  Content = "Width = 100"/>
            <Button Background ="#FFFFCCFF" Grid.Column = "1"  Content = "Width = *"/>
            <Button Background ="#FFFF9BFF" Grid.Column = "2"  Content = "Width = 2*"/>
            <Button Background ="#FFFF00FF" Grid.Column = "3"  Content = "Width = *"/>
        </Grid>
        <Grid Grid.Row = "3">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width = "100"/>
                <ColumnDefinition Width = "*"/>
                <ColumnDefinition Width = "2*"/>
                <ColumnDefinition Width = "*"/>
            </Grid.ColumnDefinitions>
            <Button Background="#00000000" Grid.Column = "0"  Content = "Width = 100"/>
            <Button Background ="#FFFFCCFF" Grid.Column = "1"  Content = "Width = 3*"/>
            <Button Background ="#FFFF9BFF" Grid.Column = "2"  Content = "Width = 6*"/>
            <Button Background ="#FFFF00FF" Grid.Column = "3"  Content = "Width = 3*"/>
        </Grid>
    </Grid>
</Page>

效果:
在这里插入图片描述
在这里插入图片描述
(1)当一个行的高度或者列的宽度设置为 ∗ * 时会占据所有的剩余空间。
(2)当多行或者多列使用 ∗ * 时剩余空间会被等量地分配给这些行或列。
(3)行或列可以在 ∗ * 之前做一个系数,如2 ∗ * 和6 ∗ * ,表示按比例其他行或列占据更多的空间。在同一个Grid中一个宽为2 ∗ * 的列的宽度是一个宽为 ∗ * 列的2倍。
(4)通过将Grid的属性IsSharedSizeScope设置成true,然后将行和列的属性SharedSizeGroup设置为一个大小写敏感的字符串,表示这个组的名称。不仅可以将一个Grid里面的行和列设置成同样的高度或宽度,甚至是不同Grid的行和列也可以设成同样的高度或宽度。代码如下:

<Page x:Class="mumu_layout.Page7"
      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" 
      mc:Ignorable="d" 
      d:DesignHeight="564" d:DesignWidth="406"
	Title="共享尺寸Demoby老顽童">
    <Grid Grid.IsSharedSizeScope = "true">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid Grid.Row = "0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width = "Auto" SharedSizeGroup = "a"/>
                <ColumnDefinition Width = "Auto" SharedSizeGroup = "a"/>
            </Grid.ColumnDefinitions>
            <Button Background="#00000000" Grid.Column = "0" Content = "SharedSizeGroup = a"/>
            <Button Background ="#FFFFCCFF" Grid.Column = "1" Content = "SharedSizeGroup = a"/>
        </Grid>
        <Grid Grid.Row = "1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width = "100"/>
                <ColumnDefinition Width = "*"/>
                <ColumnDefinition Width = "*"/>
                <ColumnDefinition Width = "*"/>
            </Grid.ColumnDefinitions>
            <Button Background="#00000000" Grid.Column = "0"  Content = "Width = 100"/>
            <Button Background ="#FFFFCCFF" Grid.Column = "1"  Content = "Width = *"/>
            <Button Background ="#FFFF9BFF" Grid.Column = "2"  Content = "Width = *"/>
            <Button Background ="#FFFF00FF" Grid.Column = "3"  Content = "Width = *"/>
        </Grid>
        <Grid Grid.Row = "2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width = "100"/>
                <ColumnDefinition Width = "*"/>
                <ColumnDefinition Width = "2*" SharedSizeGroup = "a"/>
                <ColumnDefinition Width = "*"/>
            </Grid.ColumnDefinitions>
            <Button Background="#00000000" Grid.Column = "0"  Content = "Width = 100"/>
            <Button Background ="#FFFFCCFF" Grid.Column = "1"  Content = "Width = *"/>
            <Button Background ="#FFFF9BFF" Grid.Column = "2" Content = "SharedSizeGroup = a"/>
            <Button Background ="#FFFF00FF" Grid.Column = "3"  Content = "Width = *"/>
        </Grid>
        <Grid Grid.Row = "3">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width = "100"/>
                <ColumnDefinition Width = "*"/>
                <ColumnDefinition Width = "2*"/>
                <ColumnDefinition Width = "*"/>
            </Grid.ColumnDefinitions>
            <Button Background="#00000000" Grid.Column = "0"  Content = "Width = 100"/>
            <Button Background ="#FFFFCCFF" Grid.Column = "1"  Content = "Width = 3*"/>
            <Button Background ="#FFFF9BFF" Grid.Column = "2"  Content = "Width = 6*"/>
            <Button Background ="#FFFF00FF" Grid.Column = "3"  Content = "Width = 3*"/>
        </Grid>
    </Grid>
</Page>

效果:
在这里插入图片描述
(5)GridSplitter,效果是利用GridSplitter调整元素的长和宽,代码如下:

<Page x:Class="mumu_layout.Page8"
      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" 
      mc:Ignorable="d" 
      d:DesignHeight="564" d:DesignWidth="406"
	Title="GridSplitterDemoby老顽童">
    <Grid Grid.IsSharedSizeScope = "true">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <GridSplitter Grid.Row="2" HorizontalAlignment="Stretch" 
                      VerticalAlignment="Top" Background="Black"
                      ShowsPreview="true" ResizeDirection="Rows"
                      
                      Height="5"/>

        <Grid Grid.Row = "0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width = "Auto" SharedSizeGroup = "a"/>
                <ColumnDefinition Width = "Auto" SharedSizeGroup = "a"/>
            </Grid.ColumnDefinitions>
            <Button Background="#00000000" Grid.Column = "0" Content = "SharedSizeGroup = a"/>
            <Button Background ="#FFFFCCFF" Grid.Column = "1" Content = "SharedSizeGroup = a"/>
        </Grid>
        <Grid Grid.Row = "1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width = "100"/>
                <ColumnDefinition Width = "*"/>
                <ColumnDefinition Width = "*"/>
                <ColumnDefinition Width = "*"/>
            </Grid.ColumnDefinitions>
            <Button Background="#00000000" Grid.Column = "0"  Content = "Width = 100"/>
            <Button Background ="#FFFFCCFF" Grid.Column = "1"  Content = "Width = *"/>
            <Button Background ="#FFFF9BFF" Grid.Column = "2"  Content = "Width = *"/>
            <Button Background ="#FFFF00FF" Grid.Column = "3"  Content = "Width = *"/>
        </Grid>
        <Grid Grid.Row = "2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width = "100"/>
                <ColumnDefinition Width = "*"/>
                <ColumnDefinition Width = "2*" SharedSizeGroup = "a"/>
                <ColumnDefinition Width = "*"/>
            </Grid.ColumnDefinitions>
            <GridSplitter Grid.Column="2" HorizontalAlignment="Left"
                          VerticalAlignment="Stretch" Background="Black"
                          ShowsPreview="true" Width="10"/>

            <Button Background="#00000000" Grid.Column = "0"  Content = "Width = 100" Margin="5"/>
            <Button Background ="#FFFFCCFF" Grid.Column = "1"  Content = "Width = *" Margin="5"/>
            <Button Background ="#FFFF9BFF" Grid.Column = "2" Content = "SharedSizeGroup = a" Margin="5"/>
            <Button Background ="#FFFF00FF" Grid.Column = "3"  Content = "Width = *" Margin="5"/>
        </Grid>
        <Grid Grid.Row = "3">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width = "100"/>
                <ColumnDefinition Width = "*"/>
                <ColumnDefinition Width = "2*"/>
                <ColumnDefinition Width = "*"/>
            </Grid.ColumnDefinitions>
            <Button Background="#00000000" Grid.Column = "0"  Content = "Width = 100"/>
            <Button Background ="#FFFFCCFF" Grid.Column = "1"  Content = "Width = 3*"/>
            <Button Background ="#FFFF9BFF" Grid.Column = "2"  Content = "Width = 6*"/>
            <Button Background ="#FFFF00FF" Grid.Column = "3"  Content = "Width = 3*"/>
        </Grid>
    </Grid>
</Page>

效果:
在这里插入图片描述
在这里插入图片描述

控件布局

关注控件本身

布局实际上是一个槽(slot)模型,其中每一个区域(父对象)分配给子对象一个槽,子对象能自由占用这个槽中空间的任何部分,该功能通过布局的3个属性:Margin,HorizontalAligment,VericalAligment来实现。它们都是FrameworkElement的属性。
代码如下:

<Page x:Class="mumu_layout2.Page1"
      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" 
      mc:Ignorable="d" 
      
	Title="桃树林的属性by黄药师" >
    <Border Background="LightBlue" 
          BorderBrush="Black" 
          BorderThickness="2" 
          CornerRadius="45" 
          Padding="25">
        <StackPanel Name="StackPanel1" Background = "White">
            <TextBlock FontSize="18" HorizontalAlignment="Center" Margin="0,0,0,15" Text = "StackPanel1">
            </TextBlock>
            <Border BorderThickness  = "1" BorderBrush = "black" >
                <Button Margin="5,10,15,20" >Normal</Button>
            </Border>
            <Border BorderThickness  = "1" BorderBrush = "black" >
                <Button Margin="5,10,15,20" HorizontalAlignment = "Left">Left</Button>
            </Border>
            <Border BorderThickness  = "1" BorderBrush = "black" >
                <Button HorizontalAlignment = "Right" Margin="5,10,15,20">Right</Button>
            </Border>
            <Border BorderThickness  = "1" BorderBrush = "black" >
                <Button Margin="5,10,15,20" HorizontalAlignment = "Center">Center</Button>
            </Border>
            <TextBlock>Button.Margin="5,10,15,20"</TextBlock>
        </StackPanel>
    </Border>

</Page>

在这里插入图片描述

控件旋转

代码如下:

<Page x:Class="mumu_layout2.Page2"
      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" 
      mc:Ignorable="d" 
      
	Title="桃树林的属性by黄药师" >
    <Border Background="LightBlue" 
          BorderBrush="Black" 
          BorderThickness="2" 
          CornerRadius="45" 
          Padding="25">
        <StackPanel Name="StackPanel1" Background = "White">
            <TextBlock FontSize="18" HorizontalAlignment="Center" Margin="0,0,0,15" Text = "StackPanel1">
            </TextBlock>
            <Border BorderThickness  = "1" BorderBrush = "black" >
                <Button Margin="5,10,15,20" >Normal</Button>
            </Border>
            <Border BorderThickness  = "1" BorderBrush = "black" >
                <Button Margin="5,10,15,20" HorizontalAlignment = "Left" Content="Left" Background ="#FFFFCCFF">
                    <Button.LayoutTransform>
                        <RotateTransform Angle = "15" />
                    </Button.LayoutTransform>
                </Button>
            </Border>
            <Border BorderThickness  = "1" BorderBrush = "black" >
                <Button HorizontalAlignment = "Right" Margin="5,10,15,20" Content="Right" Background ="#FFFF9BFF">
                    <Button.LayoutTransform>
                        <RotateTransform Angle = "45" />
                    </Button.LayoutTransform>
                </Button>
            </Border>
            <Border BorderThickness  = "1" BorderBrush = "black" >
                <Button Margin="5,10,15,20" HorizontalAlignment = "Center" Content="Center" Background="#FFFF00FF">
                    <Button.LayoutTransform>
                        <RotateTransform Angle = "75" />
                    </Button.LayoutTransform>
                </Button>
            </Border>
            <TextBlock>Button.Margin="5,10,15,20"</TextBlock>
        </StackPanel>
    </Border>

</Page>

效果:
在这里插入图片描述

LayoutTransform和RenderTransform

代码:

<Page x:Class="mumu_layout2.Page3"
      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" 
      mc:Ignorable="d" 
      
	Title="桃树林的属性by黄药师" >
    <Border Background="LightBlue" 
          BorderBrush="Black" 
          BorderThickness="2" 
          CornerRadius="45" 
          Padding="25">
        <StackPanel Name="StackPanel1" Background = "White">
            <TextBlock FontSize="18" HorizontalAlignment="Center" Margin="0,0,0,15" Text = "StackPanel1">
            </TextBlock>
            <Border BorderThickness  = "1" BorderBrush = "black" >
                <Button   Content="LayoutTransform">
                    <Button.LayoutTransform>
                        <RotateTransform Angle = "15" />
                    </Button.LayoutTransform>
                </Button>
            </Border>
            <Border BorderThickness  = "1" BorderBrush = "black" >
                <Button  Content="RenderTransform" >
                    <Button.RenderTransform>
                        <RotateTransform Angle = "15" />
                    </Button.RenderTransform>
                </Button>
            </Border>
            
            
        </StackPanel>
    </Border>

</Page>

效果
在这里插入图片描述
LayoutTransform参与布局,而RenderTransform并不参与。

自定义布局

要掌握自定义布局,必须了解布局的两个阶段。实际上确定控件最佳尺寸的经历了两个阶段,第一个阶段为测量(Measure)阶段,即父元素咨询子元素所期望的尺寸,从而确定自身的尺寸;第二阶段为布局(Arrange)阶段,在这个阶段,在这个期间每个父元素会告知子元素的尺寸和位置。
从编程模型来看,具体到两个重载函数:MeasureOverride和ArrangeOverride。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace mumu_layout2
{
    public class CustomPanel : Panel
    {
        // Default public constructor
        public CustomPanel()
            : base()
        {
        }

        
        protected override Size MeasureOverride(Size availableSize)
        {
            double maxChildWidth = 0.0;
            double maxChildHeight = 0.0;
            foreach (UIElement child in InternalChildren)
            {
                child.Measure(availableSize);
                maxChildWidth = Math.Max(child.DesiredSize.Width, maxChildWidth);
                maxChildHeight = Math.Max(child.DesiredSize.Height, maxChildHeight);

            }
            double idealCircumference = maxChildWidth * InternalChildren.Count;
            double idealRadius = (idealCircumference / (Math.PI * 2) + maxChildHeight);

            Size ideal = new Size(idealRadius * 2, idealRadius * 2);
            Size desired = ideal;
            if (!double.IsInfinity(availableSize.Width))
            {
                if (availableSize.Width < desired.Width)
                    desired.Width = availableSize.Width;
            }
            if (!double.IsInfinity(availableSize.Height))
            {
                if (availableSize.Height < desired.Height)
                    desired.Height = availableSize.Height;
            }
            return desired;

        }
        protected override Size ArrangeOverride(Size finalSize)
        {
            Rect layoutRect;
            if (finalSize.Width > finalSize.Height)
            {
                layoutRect = new Rect((finalSize.Width - finalSize.Height) / 2, 0, finalSize.Height, finalSize.Height);
            }
            else
            {
                layoutRect = new Rect(0, (finalSize.Height - finalSize.Width) / 2, finalSize.Width, finalSize.Width);
            }
            double angleInc = 360 / InternalChildren.Count;
            double angle = 0;
            foreach (UIElement child in InternalChildren)
            {
                Point childLocation = new Point(layoutRect.Left + (layoutRect.Width - child.DesiredSize.Width) / 2, layoutRect.Top);

                child.RenderTransform = new RotateTransform(angle, child.DesiredSize.Width / 2, finalSize.Height / 2 - layoutRect.Top);
                angle += angleInc;
                child.Arrange(new Rect(childLocation, child.DesiredSize));
            }
            return finalSize;
        }
    }

}


新建一个页面,在其中调用CutstomPanel,代码如下:

<Page x:Class="mumu_layout2.Page4"
      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:local="clr-namespace:mumu_layout2"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      mc:Ignorable="d" 
      
	Title="Page4">
    <local:CustomPanel>
        <Button Background="#00000000" MinWidth="100">1</Button>
        <Button Background ="#FFFFCCFF" MinWidth="100">2</Button>
        <Button Background ="#FFFF9BFF" MinWidth="100">3</Button>
        <Button Background ="#FFFF00FF" MinWidth="100">4</Button>
        <Button Background="#FFFFCCFF" MinWidth="100">5</Button>
    </local:CustomPanel>

</Page>

效果:
在这里插入图片描述

控件与Content

缘起
控件的出现由来已久。WPF的控件出现之前已经有多种控件框架。这些控件框架的一个关键问题是缺乏一致的灵活性。
WPF团队希望提供一个控件,并且可以用于任何地方。这就是一致的灵活性。
另外在WPF设计初期,其团队的一个宏伟目标是为UI,文档和媒体提供一个集成的平台,以按钮为例,他有一个类型为object的Content属性。

Content 模型及其家族

Content模型

从ContentControl继承的类均包含一个Content属性。
Content模型中包含一个相当重要的类ContentPresenter,该类根据需要将Content显示为一个字符串,日期,图片或者一个视频。
Content将所有元素分成两类,即UIElement类和非UIElement类,前者WPF会利用OnRender方法来显示前者所需要的内容。后者则利用一般类都会有的方法ToString来显示其内容。
Content最大限制是一个Content只允许设置一种元素,解决方案之一是将一个面板(StackPanel和Grid)设置给Content,然后在面板里放置其他元素;方案二是完全抛弃ContentControl的派生类,而使用ItemsControl以及其派生类,Content的另外一个限制是不可以将Window这样的“树根”类型的值赋值给它。

Content家族

直系
在这里插入图片描述
从ContentControl派生的类均包含一个Content属性,Button,Window,CheckBox和ToolTip这样的控件均派生自ContentControl.
HeaderContentControl继承自ContentControl,除了Content属性还包含一个Header属性。该属性为Object类型,可以包含文本,UI和媒体等多种元素,GropBox派生自该类。
ItemsControl包含了一个Content集合,Menu,ListBox,ListView,TreeView等控件派生自该类。
HeaderItemControl派生自ItemsControl,除了Content属性集合还包含一个Header属性。该属性为Object类型,可以包含文本,UI和媒体等多种元素,MenuItem派生自该类。
远亲
在这里插入图片描述
Decorator会围绕其子控件添加一些效果,如边框。它有一个Child属性,其类型为UIElement,Border类派生该类。
Panel有一群孩子属性(Children).StackPanel和Grid派生该类。
TextBlock是一个轻量级的文本控件,比Label更轻量。

经典控件

Content 控件

1. Label
WPF中的Label控件支持以键盘快捷键的方式获得焦点,可以使得与其有密切关系的控件获得焦点

<Window x:Class="mumu_label.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel Margin="5">
        <Label Target="{Binding ElementName=txtA}">Choose _A</Label>
        <TextBox Name="txtA"></TextBox>
        <Label Target="{Binding ElementName=txtB}">Choose _B</Label>
        <TextBox Name="txtB"></TextBox>
    </StackPanel>
</Window>

当按下Alt+A快捷键,光标会切换到第一个文本框;当按下Alt+B快捷键,光标会切换到第二个文本框;在WPF中通过下划线_设置快捷键的字母。
2. Button控件
在WPF中Button控件是一个可以被单击,但不能被双击的Content控件
在这里插入图片描述
(1) ButtonBase
定义了Click事件和ClickMode属性,通过该属性使用枚举可以准确控制何时触发Click事件。默认值是Release,即鼠标释放时候触发Click事件;此外还有Press(鼠标按下时)和Hover(鼠标滑过按钮时)等。
(2)Button
Button在ButtonBase的基础上增加了IsDefault和IsCancel属性,如果IsDefault属性设置为true,则即使焦点不在这个按钮上,按下回车键也会触发Click事件。IsCancel则对应的是ESC键。
(3)RepeatButton
滚动条中包含RepeatButton控件,不单独使用。它属于System.Windows.Controls.Primitives命名空间,该命名空间里一般不推荐用户使用。
(4)ToggleButton
该控件是一种在单击时可以保持状态的按钮,第一次被单击时IsChecked属性被设置成true;再一次单击则变成false。该控件的IsThreeState为true,IsChecked会有3种值,true(对应Checked事件),false(对应UnChecked事件),null(对应Indeterminate事件)。它属于System.Windows.Controls.Primitives命名空间。但可以使用CheckBox和RadioButton两个派生与它的类。
(5)CheckBox
除了外观外和ToggleButton相同。
(6)RadioButton
它具有互斥性。代码如下

<Window x:Class="mumu_RadioButtonGroups.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"  Height="300" Width="300">
    <StackPanel>
        <GroupBox Margin="5">
            <StackPanel>
                <RadioButton>Group 1</RadioButton>
                <RadioButton>Group 1</RadioButton>
                <RadioButton>Group 1</RadioButton>
                <RadioButton Margin="0,10,0,0" GroupName="Group2">Group 2</RadioButton>
            </StackPanel>
        </GroupBox>
        <GroupBox Margin="5">
            <StackPanel>
                <RadioButton>Group 3</RadioButton>
                <RadioButton>Group 3</RadioButton>
                <RadioButton>Group 3</RadioButton>
                <RadioButton Margin="0,10,0,0" GroupName="Group2">Group 2</RadioButton>
            </StackPanel>
        </GroupBox>
    </StackPanel>
</Window>

效果:
在这里插入图片描述
3. ToolTip
ToolTip控件将其内容放在一个浮动框中,当鼠标移过与之关联的控件时会显示该控件的内容,移开以后则消失,ToolTip控件不能直接放在UI元素树中,必须被赋给另一个元素的ToolTip属性(FrameworkElement和FrameContentElement中均定义了该属性)。
ToolTip不会获得焦点,而且不能单击或者其交互。有时可能我们需要在ToolTip出现或者消失时执行某种操作,ToolTip定义了open和closed事件及其属性来调节其行为。ToolTipService定义一些附加属性,能够设置在任何一个使用ToolTip的元素上并且有多个与ToolTip相同的属性,但是优先级更高。它还有一些ToolTip不具备的属性,如ShowDuration属性控制鼠标悬停在一个元素后多长时间显示ToolTip。
实例代码如下:

<Window x:Class="mumu_ToolTips.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="321" Width="301" >
    <StackPanel Margin="5" ToolTip="StackPanel tooltip">
        <Button ToolTip="This is my tooltip" ToolTipService.InitialShowDelay="5000">I have a tooltip</Button>
        <Button ToolTipService.InitialShowDelay="0" ToolTipService.BetweenShowDelay="5000">
            <Button.ToolTip>
                <ToolTip Background="#60AA4030" Foreground="White"
                 HasDropShadow="False" >
                    <StackPanel>
                        <TextBlock Margin="3" >Image and text</TextBlock>
                        <Image Source="happyface.jpg" Stretch="None" />
                        <TextBlock Margin="3" >Image and text</TextBlock>
                    </StackPanel>
                </ToolTip>
            </Button.ToolTip>
            <Button.Content>I have a fancy tooltip</Button.Content>
        </Button>
        <Button ToolTip="This is my tooltip"  ToolTipService.Placement="Bottom">Placement test</Button>
        <Button Padding="50">Does Nothing</Button>
        <TextBox TextWrapping="Wrap" MinLines="2" AutoWordSelection="True"></TextBox>
    </StackPanel>
</Window>

效果:
在这里插入图片描述

HeaderedContent控件

HeaderedContent控件是继承HeaderedContentControl而来的
1. GroupBox
GroupBox是一种用来组织多种控件的常见控件,通常用来包含多个项,但是由于它是内容控件,所以只能直接包含一项,如果需要包含多项,则必须使用一个可以包含多个子内容的中间控件,如StackPanel等。GroupBox的Header和Content属性可以被设置为任意类型的对象。

<Window x:Class="mumu_groupboxdemo.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <GroupBox>
            <GroupBox.Header>
                <WrapPanel>
                    <Image Source ="duanyuicon.jpg"/>
                    <TextBlock Text="段誉吸人内力列表:"/>
                </WrapPanel>
            </GroupBox.Header>
            <GroupBox.Content>
                <StackPanel  TextBlock.FontSize="20" >
                    <TextBlock Text="追杀木婉清的一帮人"/>
                    <TextBlock Text="云中鹤"/>
                    <TextBlock Text="段正淳等"/>
                    <TextBlock Text="燕子坞老太婆"/>
                    <TextBlock Text="鸠摩智"/>
                </StackPanel>
            </GroupBox.Content>
        </GroupBox>
    </Grid>
</Window>

效果:
在这里插入图片描述
2. Expander
Expander类似GroupBox,但是包含一个按钮,可以展开或者折叠其中包含的内容(默认处于折叠状态)。该控件定义了IsExpandered属性及Expanded/Collapsed事件,并且可以用ExpandDirection属性控制其方向。将上例改为Expander形式。
实例代码:
建立一个“ExpanderEx”的用户控件
代码如下

<Expander x:Class="mumu_expanderDemo.ExpanderEx"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Expander.Header>
        <WrapPanel>
            <Image Source ="duanyuicon.jpg" Height="36" Width="29" />
            <TextBlock Text="段誉吸人内力列表:"/>
                </WrapPanel>
    </Expander.Header>
    <Expander.Content>
        <StackPanel  TextBlock.FontSize="20" >
            <TextBlock Text="追杀木婉清的一帮人"/>
                    <TextBlock Text="云中鹤"/>
                    <TextBlock Text="段正淳等"/>
                    <TextBlock Text="燕子坞老太婆"/>
                    <TextBlock Text="鸠摩智"/>
                </StackPanel>
    </Expander.Content>
</Expander>

在窗口用这个类

<Window x:Class="mumu_expanderDemo.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:mumu_expanderDemo"
    Title="ExpanderDemo" Height="300" Width="300">
    <StackPanel>
        <local:ExpanderEx  />
        <local:ExpanderEx ExpandDirection="Left" />
        <local:ExpanderEx ExpandDirection="Right" />
        <local:ExpanderEx ExpandDirection="Up" />
    </StackPanel>
</Window>

效果:
在这里插入图片描述

Items控件

Items控件继承自ItemsControl,包含一个拥有多个Items集合的Content。每个Item可以是任意对象。ItemsControl将其内容保存在Items属性中。
Items控件除了Items属性之外,还有一个ItemsSource属性,该属性可以将一个任意类型的集合赋给Items集合,一般多用于数据绑定。
Items控件中有多个复杂控件,本节仅简单介绍ListBox,ComboBox和Menu.
ListBox
ListBox为用户提供了一个选项列表,该列表可以是固定的或动态绑定,它与ComboBox的一个显著不同是其中的所有选项可以对用户可见。
在这里插入图片描述
实例:

<Window x:Class="mumu_ListBoxDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <GroupBox Margin="5">
            <GroupBox.Header>
                <TextBlock Text="选择模式"></TextBlock>
            </GroupBox.Header>
            <GroupBox.Content>
                <StackPanel Margin="3" Background="AliceBlue" RadioButton.Checked="Radio_Checked">
                    <RadioButton Name="radioSingle">Single</RadioButton>
                    <RadioButton Name="radioMultiple">Multiple</RadioButton>
                    <RadioButton Name="radioExtended">Extended</RadioButton>
                </StackPanel>
            </GroupBox.Content>
        </GroupBox>
        <GroupBox Margin="5">
            <GroupBox.Header>
                <TextBlock>效果</TextBlock>
            </GroupBox.Header>
            <GroupBox.Content>
                <ListBox Name="lb">
                    <ListBoxItem>Item 1</ListBoxItem>
                    <ListBoxItem>Item 2</ListBoxItem>
                    <ListBoxItem>Item 3</ListBoxItem>
                    <ListBoxItem>Item 4</ListBoxItem>
                    <ListBoxItem>Item 5</ListBoxItem>
                </ListBox>
            </GroupBox.Content>
        </GroupBox>
    </StackPanel>
</Window>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace mumu_ListBoxDemo
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        private void Radio_Checked(object sender, RoutedEventArgs e)
        {
            RadioButton currentRadioBtn = (RadioButton)e.OriginalSource;
            string selectMode = currentRadioBtn.Name;
            switch (selectMode)
            {
                case "radioSingle":
                    lb.SelectionMode = SelectionMode.Single;
                    break;
                case "radioMultiple":
                    lb.SelectionMode = SelectionMode.Multiple;
                    break;
                case "radioExtended":
                    lb.SelectionMode = SelectionMode.Extended;
                    break;
            }
        }

    }
}

效果:
在这里插入图片描述
2. ComboBox
ComboBox是一种经典控件,允许用户在一个列表中选择一个Item,其中的下拉列表框可以通过单击或者按Alt+上箭头,Alt+下箭头和F4键打开并关闭。ComboBox定义了DropDownOpened和DropDownClosed事件。允许打开或者关闭下拉列表框时执行对应的操作。
实例:

<Window x:Class="mumu_comboBoxDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="天龙八部人物谱" Height="300" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="0.3*"/>
            <RowDefinition Height="0.7*"/>
        </Grid.RowDefinitions>
        <TextBlock Grid.Row ="0"  Text="天龙八部" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="25"/>
        <ComboBox Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Top" ScrollViewer.CanContentScroll ="false" IsEditable="True" MaxDropDownHeight="620"
                  ><!--.TextPath="Name"-->
            <StackPanel Orientation="Horizontal" Margin="5"  TextSearch.Text="段誉"><!--Name="段誉"-->
                <Image Source="duanyu.jpg"/>
                <StackPanel Width="200" >
                    <TextBlock Margin="5.0" FontSize="24" FontWeight="Bold" VerticalAlignment="Center" Text="段誉"/>
                    <TextBlock Margin="5.0" FontSize="14" TextWrapping="Wrap">
                    看他一袭青衫,容仪如玉,明净柔和,有着说不出的与生俱来的优雅气质。他毫无世俗间的心机,纯作一派天真,爽朗而通达,隽秀的脸上永远也不会显露出尘世间经常可以见到的冷酷傲慢的表情。他是理想中的书生形象,即使其迂腐的一面也让人觉出可喜可爱。
                    </TextBlock>
                 </StackPanel>
            </StackPanel>
            <StackPanel Orientation="Horizontal" Margin="5" TextSearch.Text="萧峰"><!--Name="萧峰"-->
                <Image Source="quanfeng.jpg"/>
                <StackPanel Width="200" >
                    <TextBlock Margin="5.0" FontSize="24" FontWeight="Bold" VerticalAlignment="Center" Text="萧峰"/>
                    <TextBlock Margin="5.0" FontSize ="14" TextWrapping="Wrap">
                    在萧峰的面前,既往的一切陈述都变得苍白和空洞,无可阻挡地进行价值的消解和缺失。萧峰的出现是空谷来风,是平地的一声春雷,是我们所有凡人琐屑生活中梦寐以求渴望的高贵气息,是英雄有力、骄傲、坚定的自白。段誉喝彩道:“好一条大汉!这定是燕赵北国的悲歌慷慨之士。”仅此一句话,就足可表现出萧峰天人般大气磅礴、神威凛凛之气势。
                    </TextBlock>
                 </StackPanel>
            </StackPanel>
            <StackPanel Orientation="Horizontal" Margin="5" TextSearch.Text="虚竹" ><!--Name="虚竹"-->
                <Image Source="xuzhu1.jpg"/>
                <StackPanel Width="200" >
                    <TextBlock Margin="5.0" FontSize="24" FontWeight="Bold" VerticalAlignment="Center" Text="虚竹"/>
                    <TextBlock Margin="5.0" FontSize ="14" TextWrapping="Wrap">
                    虚竹对佛的信仰不可置疑,但为何他却屡犯死规,更破了佛家杀戒、淫戒、荤戒三大戒。这其实是人性的力量,佛家处处限制人欲、人性,而虚竹出寺之后,内心深处的人性人欲被激发,对佛的信仰终究敌不过人性人欲的力量,最终破戒、还俗。
                    </TextBlock>
                 </StackPanel>
            </StackPanel>
        </ComboBox>
            
    </Grid>
</Window>

3. Menu
菜单是一种非常常见的控件。
实例如下:

<Window x:Class="mumu_menudemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Menu Grid.Row="0">
            <MenuItem Header="_Edit">
                <MenuItem Command="ApplicationCommands.Copy"/>
                <MenuItem Command="ApplicationCommands.Cut"/>
                <MenuItem Command="ApplicationCommands.Paste"/>
            </MenuItem>
            <MenuItem Header="_Font">
                <MenuItem Header="_Bold" IsCheckable="True"
                  Checked="Bold_Checked"
                  Unchecked="Bold_Unchecked"/>
                <MenuItem Header="_Italic" IsCheckable="True"
                  Checked="Italic_Checked"
                  Unchecked="Italic_Unchecked"/>
                <Separator/>
                <MenuItem Header="I_ncrease Font Size"
                  Click="IncreaseFont_Click"/>
                <MenuItem Header="_Decrease Font Size"
                  Click="DecreaseFont_Click"/>
            </MenuItem>
        </Menu>
        <TextBox Name="textBox1" Grid.Row="1">
            <TextBox.ContextMenu>
                <ContextMenu>
                    <MenuItem Command="ApplicationCommands.Copy"/>
                    <MenuItem Command="ApplicationCommands.Cut"/>
                    <MenuItem Command="ApplicationCommands.Paste"/>
                </ContextMenu>
            </TextBox.ContextMenu>
        </TextBox>

    </Grid>
</Window>

对应的C#文件

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace mumu_menudemo
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            textBox1.Text = "木木的菜单";
        }

        private void Bold_Checked(object sender, RoutedEventArgs e)
        {
            textBox1.FontWeight = FontWeights.Bold;
        }

        private void Bold_Unchecked(object sender, RoutedEventArgs e)
        {
            textBox1.FontWeight = FontWeights.Normal;
        }

        private void Italic_Checked(object sender, RoutedEventArgs e)
        {
            textBox1.FontStyle = FontStyles.Italic;
        }

        private void Italic_Unchecked(object sender, RoutedEventArgs e)
        {
            textBox1.FontStyle = FontStyles.Normal;
        }

        private void IncreaseFont_Click(object sender, RoutedEventArgs e)
        {
            if (textBox1.FontSize < 28)
            {
                textBox1.FontSize += 2;
            }
        }

        private void DecreaseFont_Click(object sender, RoutedEventArgs e)
        {
            if (textBox1.FontSize > 10)
            {
                textBox1.FontSize -= 2;
            }
        }
    }
}

效果:
在这里插入图片描述

Range控件

1. ProgressBar
ProgressBar主要用来表示操作进度,其重要属性有Minimum,Maximum和Value。Minimum表示该进度条的最小值;Maximum表示该进度条的最大值;Value表示进度条的当前值。当设置其IsIndeterminate属性为true时,进度条会以一定周期不停运转,这时不必设置Minimum,Maximum和Value属性。
实例,代码如下:

<Window x:Class="mumu_ProgressBarDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="200" Width="300"
        Background="LightBlue">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Center">
            <ProgressBar Name="progressbar1" Height="20" Width="200" Foreground="Red" IsIndeterminate="True"></ProgressBar>
        </StackPanel>
        <StackPanel Grid.Row="1" Orientation="Vertical"  VerticalAlignment="Center" HorizontalAlignment="Center">
            <ProgressBar Name="progressbar2" Height="20" Width="200" Foreground="Blue"></ProgressBar>
            <Button Name="btnBegin" MaxWidth="50"  Margin="10" Click="btnBegin_Click">开始</Button>
        </StackPanel> 
    </Grid>
</Window>

对应的C#代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Media.Animation;

namespace mumu_ProgressBarDemo
{
    /// <summary>
    /// Window1.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void btnBegin_Click(object sender, RoutedEventArgs e)
        {
            Duration duration = new Duration(TimeSpan.FromSeconds(10));
            DoubleAnimation doubleanimation = new DoubleAnimation(100.0, duration);
            progressbar2.BeginAnimation(ProgressBar.ValueProperty, doubleanimation);
        }
    }
}

效果:
在这里插入图片描述
2. Slider
在这里插入图片描述
实例
代码如下:
c#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;

namespace mumu_SliderDemo
{
    public class DoubleConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
        {
            Byte rgbValue = System.Convert.ToByte(value) ;
            string txtRGBValue = rgbValue.ToString();
            return txtRGBValue;
        }
        public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
        {
            string str = (string)value;
            double dbValue = double.Parse(str);
            return dbValue;
        }
    }
}

窗口代码:

<Window x:Class="mumu_SliderDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:mumu_SliderDemo"
    Title="颜色调整对话框" Height="500" Width="650">
    <Window.Resources>
        <local:DoubleConverter x:Key="Converter"></local:DoubleConverter>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="6*"></ColumnDefinition>
            <ColumnDefinition Width="4*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Border Margin="5" CornerRadius="10" Grid.Column="0" Name="border">
            <Rectangle x:Name="rec" Fill="Black">           
            </Rectangle>
        </Border>
        <StackPanel Grid.Column="1">
            <StackPanel Orientation="Horizontal" Margin="10,5,5,5">
                <TextBlock Text="R:" Margin="10,1,5,1"></TextBlock>
                <TextBox Name="txtR" Margin="5,1,5,1" MinWidth="50" 
                         Text="{Binding ElementName=RSlider,Path=Value,
                         Converter={StaticResource Converter},Mode=TwoWay}">
                </TextBox>
            </StackPanel>
            <StackPanel Orientation="Horizontal" Margin="10,5,5,5">
                <TextBlock Text="G:" Margin="10,1,5,1"></TextBlock>
                <TextBox Name="txtG" Margin="5,1,5,1" MinWidth="50"
                         Text="{Binding ElementName=GSlider,Path=Value,
                         Converter={StaticResource Converter},Mode=TwoWay}"></TextBox>
            </StackPanel>
            <StackPanel Orientation="Horizontal" Margin="10,5,5,5">
                <TextBlock Text="B:" Margin="10,1,5,1"></TextBlock>
                <TextBox Name="txtB" Margin="5,1,5,1" MinWidth="50"
                         Text="{Binding ElementName=BSlider,Path=Value,
                         Converter={StaticResource Converter},Mode=TwoWay}"></TextBox>
            </StackPanel>
            
            <StackPanel Orientation="Horizontal" Margin="10,2,5,2">
                <TextBlock Text="R" Margin="5,1,1,1" VerticalAlignment="Center"></TextBlock>
                <Slider Name="RSlider" 
                    Margin="5" Minimum="0" Maximum="255" 
                    TickFrequency="10" Ticks="0,50,100,150,200,250" 
                    TickPlacement="BottomRight" IsSnapToTickEnabled="False"
                    ValueChanged="RSlider_ValueChanged" MinWidth="220">
                </Slider>
            </StackPanel>
                    
            <StackPanel Orientation="Horizontal" Margin="10,2,5,2">
                <TextBlock Text="G" Margin="5,1,1,1" VerticalAlignment="Center"></TextBlock>
                <Slider Name="GSlider" 
                    Margin="5" Minimum="0" Maximum="255" 
                    TickFrequency="10" Ticks="0,50,100,150,200,250" 
                    TickPlacement="BottomRight" IsSnapToTickEnabled="False"
                    ValueChanged="GSlider_ValueChanged" MinWidth="220">
                </Slider>
            </StackPanel>
            <StackPanel Orientation="Horizontal" Margin="10,2,5,2">
                <TextBlock Text="B" Margin="5,1,1,1" VerticalAlignment="Center"></TextBlock>
                <Slider Name="BSlider" 
                    Margin="5" Minimum="0" Maximum="255" 
                    TickFrequency="10" Ticks="0,50,100,150,200,250" 
                    TickPlacement="BottomRight" IsSnapToTickEnabled="False" IsSelectionRangeEnabled="True"
                    ValueChanged="BSlider_ValueChanged" MinWidth="220">
                </Slider>
            </StackPanel>
        </StackPanel>
        
    </Grid>
</Window>

相对应的C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace mumu_SliderDemo
{
    /// <summary>
    /// Window1.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private Color color;
        public MainWindow()
        {
            InitializeComponent();
            
        }

        private void BSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            Update();
        }

        private void GSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            Update();
        }

        private void RSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            Update();
        }

        private void Update()
        {
            color = Color.FromRgb(Convert.ToByte(RSlider.Value), Convert.ToByte(GSlider.Value), Convert.ToByte(BSlider.Value));
            rec.Fill = new SolidColorBrush(color);
        }
    }
}

效果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值