最近看了一下wpf 越发喜欢. 边看边学,顺便做点东西. WPF 的窗体有点丑.就自己做个窗体,当学习的demo吧
效果图:
实现功能: 最大化;最小化;关闭;按钮三态; 标题栏拖动;双击标题栏最大化或者还原;鼠标在窗体边缘拖动可调整窗体大小;
1. 右上角三个按钮采用样式实现效果
1 <Style x:Key="ButtonIconStyle" TargetType="Button"> 2 <Setter Property="FontFamily" Value="/WindowResize;component/Resources/#iconfont"></Setter> 3 <Setter Property="Background" Value="Transparent"></Setter> 4 <Setter Property="Foreground" Value="Black"></Setter> 5 <Setter Property="BorderBrush" Value="Transparent"></Setter> 6 <Setter Property="Padding" Value="3,3,3,3" /> 7 <Setter Property="Template" > 8 <Setter.Value> 9 <ControlTemplate TargetType="{x:Type Button}"> 10 <StackPanel Orientation="Horizontal" VerticalAlignment="Center" > 11 <TextBlock Name="Icon" 12 Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= Content}" 13 FontSize="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path= FontSize}" 14 /> 15 </StackPanel> 16 <ControlTemplate.Triggers> 17 <Trigger Property="IsMouseOver" Value="True" > 18 <Setter Property="Background" Value="Transparent" TargetName="Icon" ></Setter> 19 <Setter Property="Foreground" Value="Gray" TargetName="Icon"></Setter> 20 </Trigger> 21 <Trigger Property="IsPressed" Value="True" > 22 <Setter Property="Background" Value="Transparent" TargetName="Icon" ></Setter> 23 <Setter Property="Foreground" Value="DarkGray" TargetName="Icon" ></Setter> 24 </Trigger> 25 </ControlTemplate.Triggers> 26 </ControlTemplate> 27 </Setter.Value> 28 </Setter> 29 30 </Style>
2. 布局 这里有一个像素的boder
1 <Border BorderThickness="1,1,1,1" BorderBrush="Black"> 2 <Grid> 3 <Grid.RowDefinitions> 4 <RowDefinition Height="30"></RowDefinition> 5 <RowDefinition Height="*"></RowDefinition> 6 </Grid.RowDefinitions> 7 <Grid Grid.Row="0" Background="YellowGreen" MouseMove="HeaderMouseMove" MouseDown="HeaderMouseDown"> 8 <Grid Height="{Binding Height, RelativeSource={RelativeSource TemplatedParent}}" 9 Width="{Binding Width, RelativeSource={RelativeSource TemplatedParent}}" Margin="0,0,0,0"> 10 <Grid.ColumnDefinitions> 11 <ColumnDefinition Width="*"/> 12 <ColumnDefinition Width="Auto"/> 13 </Grid.ColumnDefinitions> 14 <StackPanel Orientation="Horizontal" Grid.Column="0" Grid.ColumnSpan="2" > 15 <Image Source="Resources/icon.png" Width="20" Height="20" Margin="4,0,0,0"></Image> 16 <TextBlock x:Name="CustomTitle" Text="标题要长一定要长" FontSize="14" 17 Margin="4,0,0,0" VerticalAlignment="Center" /> 18 </StackPanel> 19 <StackPanel Orientation="Horizontal" Grid.Column="2" Margin="0,4,4,4" > 20 <Button Content="" Style="{StaticResource ButtonIconStyle}" FontSize="20" Click="MinClick" /> 21 <Button Content="" Style="{StaticResource ButtonIconStyle}" FontSize="16" Click="MaxClick" /> 22 <Button Content="" Style="{StaticResource ButtonIconStyle}" FontSize="20" Click="CloseClick" RenderTransformOrigin="0.52,0.273"/> 23 </StackPanel> 24 </Grid> 25 </Grid> 26 <Grid Grid.Row="1"></Grid> 27 </Grid> 28 </Border>
3. C#代码实现
- 采用win32函数获取鼠标位置
-
1 /// <summary> 2 /// 获取鼠标的坐标 3 /// </summary> 4 /// <param name="lpPoint">传址参数,坐标point类型</param> 5 /// <returns>获取成功返回真</returns> 6 [DllImport("user32.dll", CharSet = CharSet.Auto)] 7 public static extern bool GetCursorPos(out POINT pt); 8 public struct POINT 9 { 10 public int X; 11 public int Y; 12 public POINT(int x, int y) 13 { 14 this.X = x; 15 this.Y = y; 16 } 17 }
- 调整位置大小用到的类->网络获取
1 public enum HitTest : int 2 { 3 HTERROR = -2, 4 HTTRANSPARENT = -1, 5 HTNOWHERE = 0, 6 HTCLIENT = 1, 7 HTCAPTION = 2, 8 HTSYSMENU = 3, 9 HTGROWBOX = 4, 10 HTSIZE = HTGROWBOX, 11 HTMENU = 5, 12 HTHSCROLL = 6, 13 HTVSCROLL = 7, 14 HTMINBUTTON = 8, 15 HTMAXBUTTON = 9, 16 HTLEFT = 10, 17 HTRIGHT = 11, 18 HTTOP = 12, 19 HTTOPLEFT = 13, 20 HTTOPRIGHT = 14, 21 HTBOTTOM = 15, 22 HTBOTTOMLEFT = 16, 23 HTBOTTOMRIGHT = 17, 24 HTBORDER = 18, 25 HTREDUCE = HTMINBUTTON, 26 HTZOOM = HTMAXBUTTON, 27 HTSIZEFIRST = HTLEFT, 28 HTSIZELAST = HTBOTTOMRIGHT, 29 HTOBJECT = 19, 30 HTCLOSE = 20, 31 HTHELP = 21, 32 }
- 主要C#代码,很少很简单
1 private const int WM_NCHITTEST = 0x0084; 2 private readonly int agWidth = 8; //拐角宽度 3 private readonly int bThickness = 2; // 边框宽度 4 private Point mousePoint = new Point(); //鼠标坐标 5 6 protected override void OnSourceInitialized(EventArgs e) 7 { 8 base.OnSourceInitialized(e); 9 HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource; 10 if (hwndSource != null) 11 { 12 hwndSource.AddHook(new HwndSourceHook(this.WndProc)); 13 } 14 } 15 16 protected virtual IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) 17 { 18 switch (msg) 19 { 20 case WM_NCHITTEST: 21 #region 测试鼠标位置 22 if (WindowState == WindowState.Normal) 23 { 24 this.mousePoint.X = (lParam.ToInt32() & 0xFFFF); 25 this.mousePoint.Y = (lParam.ToInt32() >> 16); 26 // 窗口左上角 27 if (this.mousePoint.Y - this.Top <= this.agWidth 28 && this.mousePoint.X - this.Left <= this.agWidth) 29 { 30 handled = true; 31 return new IntPtr((int) HitTest.HTTOPLEFT); 32 33 } 34 // 窗口左下角 35 else if (this.ActualHeight + this.Top - this.mousePoint.Y <= this.agWidth 36 && this.mousePoint.X - this.Left <= this.agWidth) 37 { 38 handled = true; 39 return new IntPtr((int) HitTest.HTBOTTOMLEFT); 40 } 41 // 窗口右上角 42 else if (this.mousePoint.Y - this.Top <= this.agWidth 43 && this.ActualWidth + this.Left - this.mousePoint.X <= this.agWidth) 44 { 45 handled = true; 46 return new IntPtr((int) HitTest.HTTOPRIGHT); 47 } 48 // 窗口右下角 49 else if (this.ActualWidth + this.Left - this.mousePoint.X <= this.agWidth 50 && this.ActualHeight + this.Top - this.mousePoint.Y <= this.agWidth) 51 { 52 handled = true; 53 return new IntPtr((int) HitTest.HTBOTTOMRIGHT); 54 } 55 // 窗口左侧 56 else if (this.mousePoint.X - this.Left <= this.bThickness) 57 { 58 handled = true; 59 return new IntPtr((int) HitTest.HTLEFT); 60 } 61 // 窗口右侧 62 else if (this.ActualWidth + this.Left - this.mousePoint.X <= this.bThickness) 63 { 64 handled = true; 65 return new IntPtr((int) HitTest.HTRIGHT); 66 } 67 // 窗口上方 68 else if (this.mousePoint.Y - this.Top <= this.bThickness) 69 { 70 handled = true; 71 return new IntPtr((int) HitTest.HTTOP); 72 } 73 // 窗口下方 74 else if (this.ActualHeight + this.Top - this.mousePoint.Y <= this.bThickness) 75 { 76 handled = true; 77 return new IntPtr((int) HitTest.HTBOTTOM); 78 } 79 } 80 //else // 窗口移动 81 //{ 82 // handled = true; 83 // return new IntPtr((int)HitTest.HTCAPTION); 84 //} 85 break; 86 87 #endregion 88 } 89 return IntPtr.Zero; 90 } 91 92 private void HeaderMouseMove(object sender, MouseEventArgs e) 93 { 94 95 if (e.LeftButton == MouseButtonState.Pressed) 96 { 97 98 if (this.WindowState == WindowState.Maximized) 99 { 100 POINT px; 101 GetCursorPos(out px); 102 this.WindowState = WindowState.Normal; 103 Point p = e.GetPosition(sender as IInputElement); 104 double x = SystemParameters.WorkArea.Width;//得到屏幕工作区域宽度 105 this.Left = px.X - (p.X/x)*this.Width; 106 this.Top = px.Y - 5; 107 108 } 109 else 110 this.DragMove(); 111 } 112 } 113 114 private void MinClick(object sender, RoutedEventArgs e) 115 { 116 this.WindowState= WindowState.Minimized; 117 } 118 119 private void MaxClick(object sender, RoutedEventArgs e) 120 { 121 if (this.WindowState == WindowState.Maximized) 122 { 123 this.WindowState = WindowState.Normal; 124 } 125 else 126 { 127 this.WindowState = WindowState.Maximized; 128 129 } 130 } 131 132 private void CloseClick(object sender, RoutedEventArgs e) 133 { 134 this.Close(); 135 } 136 137 private void HeaderMouseDown(object sender, MouseButtonEventArgs e) 138 { 139 if (e.ClickCount == 2) 140 { 141 this.WindowState = this.WindowState == WindowState.Maximized 142 ? WindowState.Normal 143 : WindowState.Maximized; 144 } 145 }