赞
踩
今天说服了领导用WPF开发前端,原因就是开发相对来说比较方便,写小项目就不用前后端分离什么的了。反正就是有个机会写WPF了,真开心。我已经写了一年的Uniapp了
就是想写一个简单的变色控件。
如果想知道附加属性,就得先了解依赖属性。详细的可以看我这篇文章
知道了依赖属性之后,我解释一下附加属性是什么意思。附加属性就是为了方便在原有的控件基础上面进行细微的修改。我们先保证编译通过
附加属性的快捷键是propa
简单给TextBox添加一个附加属性
public partial class TextBlockExtension { public static int GetTest(DependencyObject obj) { return (int)obj.GetValue(TestProperty); } public static void SetTest(DependencyObject obj, int value) { obj.SetValue(TestProperty, value); } // Using a DependencyProperty as the backing store for Test. This enables animation, styling, binding, etc... public static readonly DependencyProperty TestProperty = DependencyProperty.RegisterAttached("Test", typeof(int), typeof(TextBox), new PropertyMetadata(10)); }
这样我们就能编译通过了。
<TextBlock Text="用户" wpfEx:TextBlockExtension.Test="2"/>
依赖属性有两种使用方法
样式定义
<!--一个简单的FontSize修改--> <Style x:Key="UserSelection" TargetType="TextBlock"> <!--因为Triggers只有等于判断,所以这里简单写了一下--> <Style.Triggers> <Trigger Property="wpfEx:TextBlockExtension.Test" Value="10"> <Setter Property="FontSize" Value="10" /> </Trigger> <Trigger Property="wpfEx:TextBlockExtension.Test" Value="20"> <Setter Property="FontSize" Value="20" /> </Trigger> </Style.Triggers> </Style>
简单使用
<TextBlock Text="用户"
wpfEx:TextBlockExtension.Test="10" Style="{StaticResource UserSelection}">
</TextBlock>
<TextBlock Text="用户"
wpfEx:TextBlockExtension.Test="20"
Style="{StaticResource UserSelection}">
</TextBlock>
附加属性修改
//如果想直接操控元素,得在PropertyMetadata进行操控。记得设置初始值
public static readonly DependencyProperty TestProperty =
DependencyProperty.RegisterAttached("Test", typeof(int), typeof(TextBox), new PropertyMetadata(10,(s, e) =>
{
//s是控件本身,
var mdp = s as TextBlock;
//如果控件是该元素的父组件,类似于Grid和DockPanel,就使用Parent来寻找,这里不展开
//var mdpParent = (s as FrameworkElement).Parent as TextBlock;
if (mdp != null && e.NewValue != null)
{
mdp.FontSize = (int)e.NewValue;
}
}));
<!--如果想要预览生效需要重新编译一下-->
<TextBlock Text="用户"
wpfEx:TextBlockExtension.Test="15">
</TextBlock>
<TextBlock Text="用户"
wpfEx:TextBlockExtension.Test="20">
</TextBlock>
<!--因为我们设置了默认值为10,所以这里是10-->
<TextBlock Text="用户">
</TextBlock>
<!--优先级还是依赖属性高,所以这里是30而不是默认值10-->
<TextBlock Text="用户" FontSize="30">
</TextBlock>
附加属性和依赖属性差不多,就是声明麻烦一点。因为Get,Set是需要额外写的。
控件模板一般用于按钮,我们只要会按钮的控件模板就可以了。
HandyControl的Button有IconButton的样式源码。看一下还是挺有收获的。
参考样式代码
<Style x:Key="ButtonDashedBaseStyle" BasedOn="{StaticResource ButtonBaseStyle}" TargetType="Button"> <Setter Property="Background" Value="Transparent"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <hc:DashedBorder BorderDashArray="3,2" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Background="Transparent" CornerRadius="{Binding Path=(hc:BorderElement.CornerRadius),RelativeSource={RelativeSource TemplatedParent}}"> <StackPanel Orientation="Horizontal" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="{TemplateBinding Padding}"> <Path x:Name="PathMain" Width="{TemplateBinding hc:IconElement.Width}" Height="{TemplateBinding hc:IconElement.Height}" Fill="{TemplateBinding Foreground}" SnapsToDevicePixels="True" Stretch="Uniform" Data="{TemplateBinding hc:IconElement.Geometry}"/> <ContentPresenter x:Name="ContentPresenterMain" RecognizesAccessKey="True" VerticalAlignment="Center" Margin="6,0,0,0" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> </StackPanel> </hc:DashedBorder> <ControlTemplate.Triggers> <Trigger Property="Content" Value="{x:Null}"> <Setter Property="Visibility" Value="Collapsed" TargetName="ContentPresenterMain"/> </Trigger> <Trigger Property="hc:IconElement.Geometry" Value="{x:Null}"> <Setter Property="Visibility" Value="Collapsed" TargetName="PathMain"/> <Setter Property="Margin" Value="0" TargetName="ContentPresenterMain"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
我们想写一个控件模板,如果不是很熟练,我们就先把控件模板的原型写出来,这样更利于理解。
<DockPanel> <!--这里仿照HandyControl,使用Gemotery。IconPacks怎么转Gemotery可以看我的文章--> <Border DockPanel.Dock="Top" Width="50" Height="50" CornerRadius="25" Background="DeepSkyBlue"> <Path Data="{wpfEx:MaterialGeometry Kind=BellRing}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SnapsToDevicePixels="True" Stretch="Uniform" Width="25" Height="25" Fill="White" /> </Border> <TextBlock Text="TIM登录" HorizontalAlignment="Center" /> </DockPanel>
<Style x:Key="UserSelection" TargetType="RadioButton" BasedOn="{StaticResource {x:Type RadioButton}}"> <Setter Property="Template"> <Setter.Value> <!--先按照之前的样式粘贴一下--> <ControlTemplate TargetType="RadioButton"> <DockPanel> <Border DockPanel.Dock="Top" Width="50" Height="50" CornerRadius="25" Background="DeepSkyBlue"> <Path Data="{wpfEx:MaterialGeometry Kind=BellRing}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SnapsToDevicePixels="True" Stretch="Uniform" Width="25" Height="25" Fill="White" /> </Border> <ContentPresenter x:Name="ContentPresenterMain" RecognizesAccessKey="True" VerticalAlignment="Center" Margin="6,0,0,0" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> </DockPanel> </ControlTemplate> </Setter.Value> </Setter> </Style>
然后里面能绑定的就绑定。也是照着HandyControl改的。注意这里的Banding用的是TemplateBinding
修改好的效果
<!--一个简单的FontSize修改--> <Style x:Key="UserSelection" TargetType="RadioButton" BasedOn="{StaticResource {x:Type RadioButton}}"> <Setter Property="Template"> <Setter.Value> <!--先按照之前的样式粘贴一下--> <ControlTemplate TargetType="RadioButton"> <DockPanel> <Border DockPanel.Dock="Top" Width="{TemplateBinding hc:IconElement.Width}" Height="{TemplateBinding hc:IconElement.Height}" CornerRadius="25" Background="{TemplateBinding Foreground}"> <Path Data="{TemplateBinding hc:IconElement.Geometry}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SnapsToDevicePixels="True" Stretch="Uniform" Width="25" Height="25" Fill="{TemplateBinding Background}" /> </Border> <ContentPresenter x:Name="ContentPresenterMain" RecognizesAccessKey="True" VerticalAlignment="Center" Margin="6,0,0,0" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> </DockPanel> </ControlTemplate> </Setter.Value> </Setter> </Style>
简单使用
<RadioButton Content="TIM登录"
GroupName="UserSelect"
Style="{StaticResource UserSelection}"
Foreground="DeepSkyBlue"
Background="White"
hc:IconElement.Geometry="{wpfEx:MaterialGeometry Kind=AbTesting}" />
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:wpfEx="clr-namespace:BluetoothWPF.WpfExtensions" xmlns:hc="https://handyorg.github.io/handycontrol" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <!--一个简单的FontSize修改--> <Style x:Key="UserSelection" TargetType="RadioButton" BasedOn="{StaticResource {x:Type RadioButton}}"> <Setter Property="Foreground" Value="Gray" /> <Setter Property="Template"> <Setter.Value> <!--先按照之前的样式粘贴一下--> <ControlTemplate TargetType="RadioButton"> <DockPanel> <Border DockPanel.Dock="Top" Width="70" Height="70" CornerRadius="35" x:Name="Background"> <Path Data="{TemplateBinding hc:IconElement.Geometry}" x:Name="Icon" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SnapsToDevicePixels="True" Stretch="Uniform" Width="35" Height="35" Fill="Gray" /> </Border> <ContentPresenter x:Name="ContentPresenterMain" RecognizesAccessKey="True" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="6,0,0,0" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> </DockPanel> <ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="Background" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Background}" /> <Setter TargetName="Icon" Property="Fill" Value="White" /> </Trigger> <Trigger Property="IsFocused" Value="True"> <Setter TargetName="Background" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Background}" /> <Setter TargetName="Icon" Property="Fill" Value="White" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style TargetType="RadioButton" x:Key="UserSelectioin_Admin" BasedOn="{StaticResource UserSelection}"> <Setter Property="HorizontalAlignment" Value="Right" /> <Setter Property="Margin" Value="0 0 10 0" /> <Setter Property="Background" Value="DeepSkyBlue" /> <Setter Property="hc:IconElement.Geometry" Value="{wpfEx:MaterialGeometry Kind=AccountLock}" /> <Setter Property="Content" Value="管理员登录" /> </Style> <Style TargetType="RadioButton" x:Key="UserSelectioin_User" BasedOn="{StaticResource UserSelection}"> <Setter Property="HorizontalAlignment" Value="Left" /> <Setter Property="Margin" Value="10 0 0 0" /> <Setter Property="Background" Value="Green" /> <Setter Property="hc:IconElement.Geometry" Value="{wpfEx:MaterialGeometry Kind=Account}" /> <Setter Property="Content" Value="用户" /> </Style> </ResourceDictionary>
<RadioButton Style="{StaticResource UserSelectioin_Admin}" />
<RadioButton Style="{StaticResource UserSelectioin_User}" />
HandyControl的源码看了真的是打开眼界,但是WPF的Xaml有一个无法在内部简单计算的问题。比如我想Witdh=Height = CornerRadius*2。我可能就要写个触发器了。我后面回去测试一下有没有方法可以在Xaml里面简单计算的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。