在MahApps.MetroWindow中编辑WPF控件模板触发空引用异常的解决方案咨询
在MahApps.MetroWindow中编辑WPF控件模板触发空引用异常的解决方案
我看到你在使用MahApps.MetroWindow时,通过Blend的「编辑模板→编辑副本」功能生成Button模板后,遇到了讨厌的空引用异常,这确实是Blend处理MahApps自定义控件时的常见问题,我来帮你搞定它!
问题根源
Blend在生成模板时,没有正确识别MahApps为控件扩展的附加属性,导致模板里的部分绑定路径不完整,触发了空引用。具体来说是这两处绑定错误:
ClipBorder的CornerRadius直接写了{TemplateBinding},没有绑定到MahApps的附加属性mah:ControlsHelper.CornerRadiusContentControlEx的RecognizesAccessKey同样漏写了属性名,直接用{TemplateBinding}导致绑定失效
具体修复步骤
1. 修复CornerRadius绑定
把模板里两个ClipBorder的CornerRadius绑定替换为:
CornerRadius="{Binding Path=(mah:ControlsHelper.CornerRadius), RelativeSource={RelativeSource TemplatedParent}}"
因为MahApps是通过ControlsHelper.CornerRadius附加属性来设置Button的圆角,不是Button自身的CornerRadius属性,所以必须指定正确的附加属性路径。
2. 修复RecognizesAccessKey绑定
把ContentControlEx的RecognizesAccessKey属性从{TemplateBinding}改为:
RecognizesAccessKey="{TemplateBinding RecognizesAccessKey}"
这里Blend只是漏写了要绑定的属性名,补上就好。
3. (更省心的方案)基于MahApps默认样式修改
其实你不用重写整个模板,MahApps的控件都有现成的完整样式,直接基于默认样式扩展会更简单,还能避免绑定错误:
<Style x:Key="ButtonStyle1" TargetType="{x:Type Button}" BasedOn="{StaticResource MahApps.Styles.Button}"> <!-- 只写你需要自定义的Setter,比如修改背景、圆角等 --> <Setter Property="Background" Value="{DynamicResource MahApps.Brushes.Gray10}"/> <Setter Property="mah:ControlsHelper.CornerRadius" Value="5"/> </Style>
这种方式会继承所有MahApps的默认绑定、触发器和资源,不用手动维护复杂的模板代码。
修复后的完整ButtonStyle代码
这里给你贴出修正后的完整模板代码,替换你原来的ButtonStyle1即可:
<Style x:Key="ButtonStyle1" TargetType="{x:Type Button}"> <Setter Property="Background" Value="{DynamicResource MahApps.Brushes.Gray10}"/> <Setter Property="BorderBrush" Value="{DynamicResource MahApps.Brushes.Button.Border}"/> <Setter Property="BorderThickness" Value="1"/> <Setter Property="FontFamily" Value="{DynamicResource MahApps.Fonts.Family.Button}"/> <Setter Property="FontSize" Value="{DynamicResource MahApps.Font.Size.Button}"/> <Setter Property="FontWeight" Value="Bold"/> <Setter Property="Foreground" Value="{DynamicResource MahApps.Brushes.ThemeForeground}"/> <Setter Property="MinHeight" Value="25"/> <Setter Property="Padding" Value="5 6"/> <Setter Property="SnapsToDevicePixels" Value="True"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Button}"> <Grid> <mah:ClipBorder x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{Binding Path=(mah:ControlsHelper.CornerRadius), RelativeSource={RelativeSource TemplatedParent}}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> <mah:ClipBorder x:Name="DisabledVisualElement" Background="{DynamicResource MahApps.Brushes.Control.Disabled}" CornerRadius="{Binding Path=(mah:ControlsHelper.CornerRadius), RelativeSource={RelativeSource TemplatedParent}}" IsHitTestVisible="False" Opacity="0" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> <mah:ContentControlEx x:Name="PART_ContentPresenter" ContentCharacterCasing="{Binding (mah:ControlsHelper.ContentCharacterCasing), RelativeSource={RelativeSource Mode=TemplatedParent}}" ContentStringFormat="{TemplateBinding ContentStringFormat}" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" RecognizesAccessKey="{TemplateBinding RecognizesAccessKey}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Background" TargetName="Border" Value="{DynamicResource MahApps.Brushes.Gray8}"/> <Setter Property="BorderBrush" TargetName="Border" Value="{Binding (mah:ControlsHelper.MouseOverBorderBrush), Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}"/> </Trigger> <Trigger Property="IsPressed" Value="True"> <Setter Property="Background" TargetName="Border" Value="{DynamicResource MahApps.Brushes.Gray7}"/> </Trigger> <Trigger Property="IsKeyboardFocusWithin" Value="True"> <Setter Property="BorderBrush" TargetName="Border" Value="{Binding (mah:ControlsHelper.FocusBorderBrush), Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}"/> <Setter Property="BorderThickness" TargetName="Border" Value="{Binding (mah:ControlsHelper.FocusBorderThickness), Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}"/> </Trigger> <Trigger Property="IsEnabled" Value="False"> <Setter Property="Opacity" TargetName="DisabledVisualElement" Value="0.7"/> <Setter Property="Opacity" TargetName="PART_ContentPresenter" Value="0.3"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> <Setter Property="mah:ControlsHelper.ContentCharacterCasing" Value="Upper"/> <Setter Property="mah:ControlsHelper.CornerRadius" Value="3"/> <Setter Property="mah:ControlsHelper.FocusBorderBrush" Value="{DynamicResource MahApps.Brushes.Button.Border.Focus}"/> <Setter Property="mah:ControlsHelper.FocusBorderThickness" Value="2"/> <Setter Property="mah:ControlsHelper.MouseOverBorderBrush" Value="{DynamicResource MahApps.Brushes.Button.Border.MouseOver}"/> </Style>
小提示
以后用Blend编辑MahApps控件的模板时,一定要重点检查附加属性的绑定,MahApps大量使用附加属性来扩展控件功能,Blend经常无法自动识别这些属性,容易生成不完整的绑定,这时候手动补全或者直接基于默认样式修改会更高效哦!




