WPF换肤之四:界面设计和代码设计分离

说起WPF来,除了总所周知的图形处理核心的变化外,和Winform比起来,还有一个巨大的变革,那就是真正意义上做到了界面设计和代码设计的分离。这样可以让美工和程序分开进行,而不是糅合在一块,这样做的好处当然也是显而易见的:提高了开发效率。
原先的设计方式
在我们之前设计的代码中,每当添加一个新的窗体的时候,我总是会在这个新的窗体的XAML文件中加入如下的代码,以便使样式能够应用上去:

双击代码全选

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

View Code 

    

<Window x:Class="WpfApplication1.MsgWindow"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="TestWindow" Height="391" Width="418" WindowStyle="None" AllowsTransparency="True" Background="Transparent" OpacityMask="White" ResizeMode="NoResize" PreviewMouseMove="ResetCursor" WindowStartupLocation="CenterScreen">

    <Grid Background="Transparent">

            <Border BorderThickness="5" BorderBrush="DarkGreen"  CornerRadius="10,10,10,10" MouseMove="DisplayResizeCursor" PreviewMouseDown="Resize" Name="top">

            <Border.Background>

                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                    <GradientStop Color="#eee"/>

                </LinearGradientBrush>

            </Border.Background>

            <Grid>

               <!--这里放置UIElement.-->

            </Grid>

            </Border>

    </Grid>

</Window>

 

然后,在后台中,为了使窗体能够在最大化时不遮蔽任务栏,拖拉窗体边缘能够改变窗口大小,点按窗体可以实现拖拉的时候,在后台加入了如下的代码:

双击代码全选

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

View Code 

    

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.Shapes;

using System.Windows.Interop;

using System.Diagnostics;

using System.Runtime.InteropServices;

    

namespace WpfApplication1

{

    /// <summary>

    /// Interaction logic for TestWindow.xaml

   

    /// </summary>

    public partial class MsgWindow : Window

    {

        private const int WM_SYSCOMMAND = 0x112;

        private HwndSource hs;

        IntPtr retInt = IntPtr.Zero;

    

        public MsgWindow()

        {

            InitializeComponent();

            this.SourceInitialized += new EventHandler(WSInitialized);

        }

    

        void WSInitialized(object sender, EventArgs e)

        {

            hs = PresentationSource.FromVisual(this) as HwndSource;

            hs.AddHook(new HwndSourceHook(WndProc));

        }

    

       public double relativeClip = 10;

    

        public enum ResizeDirection

        {

            Left = 1,

            Right = 2,

            Top = 3,

            TopLeft = 4,

            TopRight = 5,

            Bottom = 6,

            BottomLeft = 7,

            BottomRight = 8,

        }

    

        [DllImport("user32.dll", CharSet = CharSet.Auto)]

        private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    

        private void ResizeWindow(ResizeDirection direction)

        {

            SendMessage(hs.Handle, WM_SYSCOMMAND, (IntPtr)(61440 + direction), IntPtr.Zero);

        }

    

        private void ResetCursor(object sender, MouseEventArgs e)

        {

            if (Mouse.LeftButton != MouseButtonState.Pressed)

            {

                this.Cursor = Cursors.Arrow;

            }

        }

    

        private void Resize(object sender, MouseButtonEventArgs e)

        {

            Border clickedBorder = sender as Border;

    

            Point pos = Mouse.GetPosition(this);

            double x = pos.X;

            double y = pos.Y;

            double w = this.ActualWidth;

            double h = this.ActualHeight;

    

            if (x <= relativeClip & y <= relativeClip) // left top

            {

                this.Cursor = Cursors.SizeNWSE;

                ResizeWindow(ResizeDirection.TopLeft);

            }

            if (x >= w - relativeClip & y <= relativeClip) //right top

            {

                this.Cursor = Cursors.SizeNESW;

                ResizeWindow(ResizeDirection.TopRight);

            }

    

            if (x >= w - relativeClip & y >= h - relativeClip) //bottom right

            {

                this.Cursor = Cursors.SizeNWSE;

                ResizeWindow(ResizeDirection.BottomRight);

            }

    

            if (x <= relativeClip & y >= h - relativeClip)  // bottom left

            {

                this.Cursor = Cursors.SizeNESW;

                ResizeWindow(ResizeDirection.BottomLeft);

            }

    

            if ((x >= relativeClip & x <= w - relativeClip) & y <= relativeClip) //top

            {

                this.Cursor = Cursors.SizeNS;

                ResizeWindow(ResizeDirection.Top);

            }

    

            if (x >= w - relativeClip & (y >= relativeClip & y <= h - relativeClip)) //right

            {

                this.Cursor = Cursors.SizeWE;

                ResizeWindow(ResizeDirection.Right);

            }

    

            if ((x >= relativeClip & x <= w - relativeClip) & y > h - relativeClip) //bottom

            {

                this.Cursor = Cursors.SizeNS;

                ResizeWindow(ResizeDirection.Bottom);

            }

    

            if (x <= relativeClip & (y <= h - relativeClip & y >= relativeClip)) //left

            {

                this.Cursor = Cursors.SizeWE;

                ResizeWindow(ResizeDirection.Left);

            }

        }

    

        private void DisplayResizeCursor(object sender, MouseEventArgs e)

        {

            Border clickBorder = sender as Border;

    

            Point pos = Mouse.GetPosition(this);

            double x = pos.X;

            double y = pos.Y;

            double w= this.ActualWidth;

            double h= this.ActualHeight;

    

            this.label1.Content = x + "--" + y;

    

            if (x <= relativeClip & y <= relativeClip) // left top

            {

                this.Cursor = Cursors.SizeNWSE;

            }

            if (x >= w - relativeClip & y <= relativeClip) //right top

            {

                this.Cursor = Cursors.SizeNESW;

            }

    

            if (x >= w - relativeClip & y >= h - relativeClip) //bottom right

            {

                this.Cursor = Cursors.SizeNWSE;

            }

    

            if (x <= relativeClip & y >= h - relativeClip)  // bottom left

            {

                this.Cursor = Cursors.SizeNESW;

            }

    

            if ((x >= relativeClip & x <= w - relativeClip) & y <= relativeClip) //top

            {

                this.Cursor = Cursors.SizeNS;

            }

    

            if (x >= w - relativeClip & (y >= relativeClip & y <= h - relativeClip)) //right

            {

                this.Cursor = Cursors.SizeWE;

            }

    

            if ((x >= relativeClip & x <= w - relativeClip) & y > h - relativeClip) //bottom

            {

                this.Cursor = Cursors.SizeNS;

            }

    

            if (x <= relativeClip & (y <= h - relativeClip & y >= relativeClip)) //left

            {

                this.Cursor = Cursors.SizeWE;

            }

        }

    

        private void button1_Click(object sender, RoutedEventArgs e)

        {

            this.WindowState = (this.WindowState == WindowState.Normal ? WindowState.Maximized : WindowState.Normal);

        }

        #region 这一部分用于最大化时不遮蔽任务栏

        private static void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam)

        {

    

            MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));

    

            // Adjust the maximized size and position to fit the work area of the correct monitor

            int MONITOR_DEFAULTTONEAREST = 0x00000002;

            System.IntPtr monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);

    

            if (monitor != System.IntPtr.Zero)

            {

    

                MONITORINFO monitorInfo = new MONITORINFO();

                GetMonitorInfo(monitor, monitorInfo);

                RECT rcWorkArea = monitorInfo.rcWork;

                RECT rcMonitorArea = monitorInfo.rcMonitor;

                mmi.ptMaxPosition.x = Math.Abs(rcWorkArea.left - rcMonitorArea.left);

                mmi.ptMaxPosition.y = Math.Abs(rcWorkArea.top - rcMonitorArea.top);

                mmi.ptMaxSize.x = Math.Abs(rcWorkArea.right - rcWorkArea.left);

                mmi.ptMaxSize.y = Math.Abs(rcWorkArea.bottom - rcWorkArea.top);

            }

    

            Marshal.StructureToPtr(mmi, lParam, true);

        }

    

        /// <summary>

        /// POINT aka POINTAPI

        /// </summary>

        [StructLayout(LayoutKind.Sequential)]

        public struct POINT

        {

            /// <summary>

            /// x coordinate of point.

            /// </summary>

            public int x;

            /// <summary>

            /// y coordinate of point.

            /// </summary>

            public int y;

    

            /// <summary>

            /// Construct a point of coordinates (x,y).

            /// </summary>

            public POINT(int x, int y)

            {

                this.x = x;

                this.y = y;

            }

        }

    

        /// <summary>

        /// 窗体大小信息

        /// </summary>

        [StructLayout(LayoutKind.Sequential)]

        public struct MINMAXINFO

        {

            public POINT ptReserved;

            public POINT ptMaxSize;

            public POINT ptMaxPosition;

            public POINT ptMinTrackSize;

            public POINT ptMaxTrackSize;

        };

        /// <summary> Win32 </summary>

        [StructLayout(LayoutKind.Sequential, Pack = 0)]

        public struct RECT

        {

            /// <summary> Win32 </summary>

            public int left;

            /// <summary> Win32 </summary>

            public int top;

            /// <summary> Win32 </summary>

            public int right;

            /// <summary> Win32 </summary>

            public int bottom;

    

            /// <summary> Win32 </summary>

            public static readonly RECT Empty = new RECT();

    

            /// <summary> Win32 </summary>

            public int Width

            {

                get { return Math.Abs(right - left); }  // Abs needed for BIDI OS

            }

            /// <summary> Win32 </summary>

            public int Height

            {

                get { return bottom - top; }

            }

    

            /// <summary> Win32 </summary>

            public RECT(int left, int top, int right, int bottom)

            {

                this.left = left;

                this.top = top;

                this.right = right;

                this.bottom = bottom;

            }

    

    

            /// <summary> Win32 </summary>

            public RECT(RECT rcSrc)

            {

                this.left = rcSrc.left;

                this.top = rcSrc.top;

                this.right = rcSrc.right;

                this.bottom = rcSrc.bottom;

            }

    

            /// <summary> Win32 </summary>

            public bool IsEmpty

            {

                get

                {

                    // BUGBUG : On Bidi OS (hebrew arabic) left > right

                    return left >= right || top >= bottom;

                }

            }

            /// <summary> Return a user friendly representation of this struct </summary>

            public override string ToString()

            {

                if (this == RECT.Empty) { return "RECT {Empty}"; }

                return "RECT { left : " + left + " / top : " + top + " / right : " + right + " / bottom : " + bottom + " }";

            }

    

            /// <summary> Determine if 2 RECT are equal (deep compare) </summary>

            public override bool Equals(object obj)

            {

                if (!(obj is Rect)) { return false; }

                return (this == (RECT)obj);

            }

    

            /// <summary>Return the HashCode for this struct (not garanteed to be unique)</summary>

            public override int GetHashCode()

            {

                return left.GetHashCode() + top.GetHashCode() + right.GetHashCode() + bottom.GetHashCode();

            }

    

    

            /// <summary> Determine if 2 RECT are equal (deep compare)</summary>

            public static bool operator ==(RECT rect1, RECT rect2)

            {

                return (rect1.left == rect2.left && rect1.top == rect2.top && rect1.right == rect2.right && rect1.bottom == rect2.bottom);

            }

    

            /// <summary> Determine if 2 RECT are different(deep compare)</summary>

            public static bool operator !=(RECT rect1, RECT rect2)

            {

                return !(rect1 == rect2);

            }

        }

    

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]

        public class MONITORINFO

        {

            /// <summary>

            /// </summary>            

            public int cbSize = Marshal.SizeOf(typeof(MONITORINFO));

    

            /// <summary>

            /// </summary>            

            public RECT rcMonitor = new RECT();

    

            /// <summary>

            /// </summary>            

            public RECT rcWork = new RECT();

    

            /// <summary>

            /// </summary>            

            public int dwFlags = 0;

        }

    

        [DllImport("user32")]

        internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);

    

        [DllImport("User32")]

        internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags);

        #endregion

    

        private void MyMacClass_SourceInitialized(object sender, EventArgs e)

        {

            hs = PresentationSource.FromVisual((Visual)sender) as HwndSource;

            hs.AddHook(new HwndSourceHook(WndProc));

        }

    

        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)

        {

            switch (msg)

            {

                case 0x0024:/* WM_GETMINMAXINFO */

                    WmGetMinMaxInfo(hwnd, lParam);

                    handled = true;

                    break;

                default: break;

            }

            return (System.IntPtr)0;

        }

    

    }

}

 

如果按照上面的设计,那么每加入一个新的窗体,都要重复上面的两个步骤的话,加入一个工程中需要加入的新窗体特别多,估计这种操作足以让一个正常人疯掉了。并且假如以后border的颜色要修改,那得修改多少页面啊~~~

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

Grow your business fast with

Suku