贵州大地建设集团网站,企业网站设计公司,做网站营销公司排名,做啤酒行业的网站[WPF疑难] 继承自定义窗口 原文 [WPF疑难] 继承自定义窗口 [WPF疑难] 继承自定义窗口 周银辉 项目中有不少的弹出窗口#xff0c;按照美工的设计其外边框#xff08;包括最大化#xff0c;最小化#xff0c;关闭等按钮#xff09;自然不同于Window自身的#xff0c;但每个… [WPF疑难] 继承自定义窗口 原文 [WPF疑难] 继承自定义窗口 [WPF疑难] 继承自定义窗口 周银辉 项目中有不少的弹出窗口按照美工的设计其外边框包括最大化最小化关闭等按钮自然不同于Window自身的但每个弹出框的外边框都是一样的。对其中一个窗口而言我们要取消其Window边框并在右上角摆上三个按钮并编写其点击事件等但若每个弹出窗口都按照这种方式做一遍就太土了。我们想避免重复劳动最自然的联想到了“继承”。但WPF给我们找了若干麻烦被挫败了几次。今天经过2小时的奋战终于搞定了分享一下。 挫败1继承时编译错误 假设我们写好的父窗口类为BaseWindow对应BaseWindow.cs和BaseWindow.xaml, 要继承它的窗口为Window1对应Window1.cs和Window1.xaml我们常常进行的动作是将VS为我们自动生成的代码中的如下语句 public partial class Window1 : Window 修改成 public partial class Window1 : BaseWindow 但编译后你会得到一个错误Window1有着不同的基类。 这是因为在window1.xaml中 Window xmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:xhttp://schemas.microsoft.com/winfx/2006/xaml x:ClassInheritWindowDemo.Window1 Width300 Height300 Grid x:NameLayoutRoot/ /Window 我们的Window继承了Window类打开Window1.g.cs也可以看到这一点这是VS自动生成的一个中间文件可以在Window1的InitializeComponent()方法上“转到定义”来跳转到该文件也可以在ObjDebug目录下找到。这就使得我们的Window1同时继承Window和BaseWindow类多继承是不被允许的。 那么自然地需要修改Window1.xaml将其中的根“Window”修改成我们的BaseWindow src:BaseWindow xmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:xhttp://schemas.microsoft.com/winfx/2006/xaml x:ClassInheritWindowDemo.Window1 xmlns:srcclr-namespace:InheritWindowDemo Height300 Width300 Grid /Grid /src:BaseWindow 心想这下可以编译通过了吧抱歉不行又得到另一个编译错误src:BaseWindow不能是Xaml文件的根因为它是由Xaml定义的目前我避免这个问题的办法是让BaseWindow仅仅在C#中定义即没有BaseWindow.xaml,只有BaseWindow.cs。 OK编译顺利通过继承成功。 挫败2外边框包括最小化最大化和关闭按钮放在哪里 明显不能作为BaseWindow的内容这是因为继承了BaseWindow的子类窗口比如Window1会覆盖BaseWindow的内容。 假设BaseWindow这样编写 public BaseWindow() { Grid grid new Grid(); Button minBtn new Button(); Button maxBtn new Button(); Button closeBtn new Button(); //something to ini these buttons grid.Children.Add(minBtn); grid.Children.Add(maxBtn); grid.Children.Add(closeBtn); this.Content grid; } 当子类Window1如下定义时 src:BaseWindow xmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:xhttp://schemas.microsoft.com/winfx/2006/xaml x:ClassInheritWindowDemo.Window1 xmlns:srcclr-namespace:InheritWindowDemo Height300 Width300 Grid TextBlock Texthi , i am window1/ /Grid /src:BaseWindow 这样以来Window1中的Grid和TextBlock会覆盖BaseWindow的内容而仅仅看到“hiI am window1”的文本块而没有最小化最大化以及关闭按钮了。 事实上我们应该反过来想Window也是一个控件与其他控件一样其外观及其外观中的视觉元素仍然是由其Style和ControlTemplate来定义的。想到这里一切就变得简单了我们应该将窗口外边框包括最小化最大化和关闭按钮定义在其Template中其他一些属性比如是否支持透明等定义在Style中 其Template如下 ControlTemplate x:KeyBaseWindowControlTemplate TargetType{x:Type Window} DockPanel LastChildFillTrue !--外边框-- Border WidthAuto HeightAuto DockPanel.DockTop Background#FF7097D0 CornerRadius4,4,0,0 x:NameborderTitle StackPanel HorizontalAlignmentRight OrientationHorizontal !--最小化按钮-- Button ContentMin x:NamebtnMin / !--最大化按钮-- Button ContentMax x:NamebtnMax / !--关闭按钮-- Button ContentClose x:NamebtnClose / /StackPanel /Border Border Background{TemplateBinding Background} BorderBrush{TemplateBinding BorderBrush} BorderThickness{TemplateBinding BorderThickness} WidthAuto HeightAuto DockPanel.DockTop CornerRadius0,0,4,4 AdornerDecorator ContentPresenter / /AdornerDecorator /Border /DockPanel /ControlTemplate 其Style如下 Style x:KeyBaseWindowStyle TargetType{x:Type Window} Setter PropertyTemplate Value{StaticResource BaseWindowControlTemplate}/ Setter PropertyAllowsTransparency ValueTrue / Setter PropertyWindowStyle ValueNone / Setter PropertyBorderBrush Value#FF7097D0 / Setter PropertyBorderThickness Value4,0,4,4 / !—Something else-- /Style 然后在BaseWindow的构造函数中指定其Style为我们定义的样式 private void InitializeStyle() { this.Style (Style) App.Current.Resources[BaseWindowStyle]; } 这样一来所有继承了BaseWindow的窗体都有我们统一定义的外观了。 挫败3让外边框包括最小化最大化和关闭按钮响应事件 只有外观还不够至少得有鼠标事件吧。那最小化事件来说要做的事情是找到定义在ControlTemplate中的btnMin这个Button控件然后当其被点击时该ControlTemplate被应用到的那个窗体被最小化。 FrameworkTemplate.FindName(string name, FrameworkElement templatedParent)方法可以做帮助我们找到指定的FrameworkTemplate被应用到templatedParent上后具有name名称的控件。 ControlTemplate baseWindowTemplate (ControlTemplate)App.Current.Resources[BaseWindowControlTemplate]; Button minBtn (Button)baseWindowTemplate.FindName(btnMin, this); minBtn.Click delegate { this.WindowState WindowState.Minimized; }; 其他事件同理不过值得提醒的是上面这样的代码应该在窗体的Style和Template被应用之后比如你可以在Loaded后编写使用上面的代码而不是直接放在构造方法中否则FrameworkTemplate.FindName方法将返回null。 至此问题搞定。下载DEMOhttp://files.cnblogs.com/zhouyinhui/InheritWindowDemo.zip posted on 2013-11-26 19:57 NET未来之路 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/lonelyxmas/p/3444011.html