还是那句话:学习微软的东西,自学就得了;不过比较费劲而已;
学会:Google 别人的示例、经验;还有:MSDN的文档查阅;
MSDN WPF技术资源库URL:http://msdn.microsoft.com/zh-cn/library/ms754130.aspx
1)、WPF,中如何加载一个.xaml文件,并转为:Window对象实例:
加载、解析XAML
WPF的运行时XMAL解析器公开两个类:
System.Windows.Markup下的:XamlReader、XamlWriter;
XamlReader.Load();
XamlWriter.Save();
Load:
//假设有一文件:MyWindow.xaml
Window window = null;
using (FileStream fs = new FileSteam("MyWindow.xaml", FileMode.Open, FileAccess.Read))
{
//获得根元素,该元素是一个Window对象
window = (Window)XmalReader.Load(fs);
}
//根据元素名称来查找元素对象
//如:以上的MyWindow.xaml文件中,有定义一个按钮为:
<Button x:Name="okButton">OK</Button>
//那么就可以通过window的FindName方法来获取元素对象Button okButton = (Button)window.FindName("okButton")
//FindName是继承自FrameworkElement 类的,MSDN文档介绍该类:
//http://msdn.microsoft.com/zh-cn/library/system.windows.frameworkelement.aspx
Save:
string xamlStr = XamlWriter.Save(window);
[继续在写...]
2)、分别需要了解,WPF目前提供的一般常用的布局控件:
都在:System.Windows.Controls命名空间低下的:
Canvas(画布)、DockPanel(停靠布局)、Grid(表格)、StackPanel(堆栈布局)、VirtualizingPanel(虚堆栈布局)、WrapPanel(覆盖布局)
Grid(表格):http://wenku.baidu.com/view/5e483b0dba1aa8114431d99b.html
3)、在学习WPF过程中,发现有个挺好用的工具:Xaml浏览工具:XamlPad
使用效果图:
4)、Grid 布局控件的简单使用
xaml源码:
<UserControl x:Class="TestWpfProject.MyGridControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" Height="250" Width="800">
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="50"/>
<RowDefinition Height="25"/>
<RowDefinition Height="60"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="2" FontSize="14" HorizontalAlignment="Center" VerticalAlignment="Center">VerticalAlignment Sample</TextBlock>
<Button Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center">Button 1 (Top)</Button>
<Button Grid.Row="2" Grid.Column="2" HorizontalAlignment="Center">Button 2 (Botton)</Button>
<Button Grid.Row="3" Grid.Column="3" VerticalAlignment="Center">Button 3 (Center)</Button>
<Button Grid.Row="4" Grid.Column="0">Button 4 (Stretch)</Button>
<Button Grid.Row="5" Grid.Column="1">Button 5 (Stretch)</Button>
</Grid>
</UserControl>
效果图:
5)、DockPanel 的布局:
xaml源码:
<UserControl x:Class="TestWpfProject.MyDockPanelControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" Width="500">
<DockPanel>
<DockPanel DockPanel.Dock="Top" LastChildFill="True" DataContext="SliderBindingData">
<Label Content="Slider's Value : "/>
<TextBox Text="This is Text"/>
</DockPanel>
<Button DockPanel.Dock="Top" Content="Button"/>
<Button DockPanel.Dock="Top" Content="Button"/>
<Slider DockPanel.Dock="Bottom" Maximum="100" Minimum="0" Name="slider1"/>
</DockPanel>
</UserControl>
效果图:
在选择,DockPanel还是StackPanel的选择,可以看看MSDN的一篇文章:
http://msdn.microsoft.com/zh-cn/library/vstudio/ms754213.aspx
从中,我们可以看到,DockPanel会影响内部子元素的尺寸大小;而StackPanel则不会,而是对子元素的显示进行裁剪;
执行效果图:
6)、Binding(可视元素与数据的绑定):
Binding的介绍,这博客里介绍得还挺详细:
http://blog.youkuaiyun.com/iamsupercola/article/details/7041996
xaml源码:
<UserControl x:Class="TestWpfProject.MyDockPanelControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:data="clr-namespace:TestWpfProject.TestNotificationObject"
mc:Ignorable="d" Width="500" Name="myControl" >
<DockPanel>
<DockPanel DockPanel.Dock="Top" LastChildFill="True">
<Label Content="Slider's Value : "/>
<TextBox Text="{Binding ElementName=myControl, Path=SliderBindingData.V1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DockPanel>
<Button DockPanel.Dock="Top" Content="Button"/>
<Button DockPanel.Dock="Top" Content="Button"/>
<Slider DockPanel.Dock="Top" Maximum="100" Minimum="0" Name="slider1" Value="{Binding ElementName=myControl, Path=SliderBindingData.V1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DockPanel>
</UserControl>
<!--以下是第二种方法,把上面的注释掉,把下面的注释去掉,运行即可看到实现-->
<!--<UserControl x:Class="TestWpfProject.MyDockPanelControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:data="clr-namespace:TestWpfProject.TestNotificationObject"
mc:Ignorable="d" Width="500" >
<![CDATA[
//注意上面的xml命名空间中,声明了一个自定义的:xmlns:data="clr-namespace:TestWpfProject.TestNotificationObject",
//然后在下面的:DockPanel.DataContext属性中,会使用到
//属性内容为:<data:NotifierObject>的对象(你可以理解为:一个标签就对应着一个对象实例),而这个实例是:data命名空间低下的:NotificationObject类对象,
//而data命名空间的内容实际上为:"clr-namespace:TestWpfProject.TestNotificationObject"
//可理解为:.cs代码中的:using data = TestWpfProject.TestNotificationObject;的意思,就是命名空间的别名
//注意下面的TextBox中的Text属性Bingding时,没有像上面的,多了一个:ElementName属性,这个是在不使用上下文数据对象(就是在本身DataContext数据对象,或是父级(的父级)的DataContext属性)时而直接与可视元素的属性数据作绑定用的;
//下面的是直接绑定了,myControl.SliderBindingData.V1属性;
//ElementName=myControl, Path=ElementName元素对应的属性内容,而myControl(当前控件名称)下我定义了:
//所以Path=SliderBindingData.V1,其实是:Path=(myControl.)SliderBindingData.V1;(myControl.)是我这边为了大家理解而加上去的
//至于还面还有:Mode就是数据与可视元素之间的相互更新方式,这里不多说中,直接F1 MSDN查看;
//过有后面的:UpdateSourceTrigger也是一样
/*
public class NotifierObject : NotificationObject//下面的MyDockPanelControl中会使用到的类型
{
//add PropertyChanged event to handle, when Raise property changed
private float v1;
public float V1
{
get { return v1; }
set
{
float v = (float)Math.Round(value, 2);
//float v = (float)decimal.Round((decimal)value, 2);
if (v1 != v)
{
v1 = v;
RaisePropertyChanged(() => V1);
}
}
}
}
public partial class MyDockPanelControl : UserControl
{
public NotifierObject SliderBindingData { get; set; }//注意这里
public MyDockPanelControl()
{
SliderBindingData = new NotifierObject();
InitializeComponent();
SliderBindingData.PropertyChanged += SliderBindingData_PropertyChanged;
}
void SliderBindingData_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
//NotifierObject no = sender as NotifierObject;
//MessageBox.Show("NotifierObject.V1 value had changed, value : " + no.V1);
}
}
*/
]]>
<DockPanel>
<DockPanel.DataContext>
<data:NotifierObject />
</DockPanel.DataContext>
<DockPanel DockPanel.Dock="Top" LastChildFill="True">
<Label Content="Slider's Value : "/>
<TextBox Text="{Binding Path=V1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DockPanel>
<Button DockPanel.Dock="Top" Content="Button"/>
<Button DockPanel.Dock="Top" Content="Button"/>
<Slider DockPanel.Dock="Top" Maximum="100" Minimum="0" Name="slider1" Value="{Binding Path=V1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DockPanel>
</UserControl>-->
效果图:(Slider's Value标签右边的文本框的Text属性值,与最下面的Slider控件的Value属性值都分别Binding了数据)
7)、不规则窗体
需要用到:Microsoft Expression Studio
可以在这里找到破解版的来使用:Expression Studio 4 破解
http://www.silverlightchina.net/html/study/WPF/2012/0624/16902.html
http://www.cnblogs.com/SkyD/archive/2008/07/13/1242044.html
8)、WPF命令:
使用WPF的命令制机,制作一些简单的命令监听,并制作成命令历史记录,并实现,类似:撤消(Undo)的功能;
测试源码项目为:MonitorCommands
9)、WPF 自定义数据转换器,官方的介绍:
http://msdn.microsoft.com/zh-cn/library/aa970913.aspx
10)、WPF 样式、触发器:
StyleTriggersSetterTestingProject
11)、WPF 实现九宫格位置拉伸:
http://www.silverlightchina.net/html/study/WPF/2012/1215/20850.html
12)、Path.Data在xaml中的各种赋值,值写法:
http://www.silverlightchina.net/html/study/WPF/2011/0116/4927.html
也可以在代码这么写成字符串,再使用:GemotryConvertor对象去转换;
13)、WPF中,如何对一个可象对象栅格化:
CodeProject的DEMO,非常有用,我把他下载,保存到网盘,以便哪天,源网站把相关资源删除。
http://www.codeproject.com/Articles/103184/How-to-Render-Bitmap-or-to-Print-a-Visual-in-WPF#
14)、关于Adorner的一个详细介绍文章:
用于制作,Tips,或是普通元素上层显示的提示信息,挺有用;
http://www.cnblogs.com/loveis715/archive/2012/03/31/2427734.html
15)、Drag and Drog Swap Items(拖动、拖拽,实现,子项之间的效换效果):
我存到网盘了:在CodeProject下你还得注册帐号;下我这个免了这流程,呵呵:
ListViewDragDropManager_src.zip
http://www.codeproject.com/Articles/17266/Drag-and-Drop-Items-in-a-WPF-ListView
16)、CaptureMouse与ReleaseMouseCapture的作用:
http://www.cnblogs.com/xwlyun/archive/2012/09/12/2681585.html
17)、自定义Expander控件:
不多说,CodeProject的总是精品:
http://www.codeproject.com/Articles/248112/Templating-WPF-Expander-Control
18)、国外WPF Mahapps.metro开源项目,很吊的项目:
首页:http://mahapps.com/MahApps.Metro/#
开源Github:https://github.com/MahApps/MahApps.Metro
19)、另一个比较轻量级开源项目的:
同时提供了一些免费xaml矢量图标(icon)非常赞!
图标提供地址:http://modernuiicons.com/
20)、WPF 国外视频网:Youtube教程:
其中看了一篇MVVM的教程,我自己重新写了一个DEMO:MVVM_Demo
21)、MSDN、CNBLOG的一些ICommand使用扩展中UI上的DEMO:
MSDN:http://msdn.microsoft.com/zh-cn/library/system.windows.input.icommandsource.command.aspx
CNBLOG:http://www.cnblogs.com/xiwang/archive/2012/07/23/2604924.html
22)、WPF 文本(TextBlock)描边:
1、转为WriteableBitmap再对像素点设置颜色,虽然不是最好的方法,但是思路不错:
http://www.cnblogs.com/webgames/archive/2010/09/18/1829814.html
2、shader 描边,也是非常不错的一个,不过这个是SL的:
http://www.cnblogs.com/ashei/archive/2011/02/12/1952243.html
3、还有另一个,思路非常值得推荐,CodeProject下的,文本描边的各种风格,Cool得要命:
http://www.codeproject.com/Articles/42529/Outline-Text
4、描边的好几种方法:(优快云的:野比,把第1、2、3点也包括中内,非常不错的总结!)
http://bbs.youkuaiyun.com/topics/390070159
23)、WPF 的HLSL(WPF Pixel Shader : PS)学习:
有一个介绍相关的国外网站,有DEMO,与视频介绍,还有:文档:
信息介绍:
http://channel9.msdn.com/shows/Continuum/WPFFXDemo/
视频介绍:
http://channel9.msdn.com/shows/Continuum/WPFFXDemo/
文档:
https://skydrive.live.com/?cid=123ec1ed6c72a14a&id=123EC1ED6C72A14A%21169
还要把相关文档下载下来了:
24、如何获取:DataTemplate的指定元素:
如:xaml模板内有这定的定义:
<ListView.View>
<GridView>
<GridViewColumn Header="Visible" Width="40">
<GridViewColumn.CellTemplate>
<DataTemplate>
<baseControl:DesignerLayerOptionMenu x:Name="Eyes" Margin="5, 5, 0, 5" Width="16" Height="16"
SelectedIcon="../Resources/Images/DesignerLayers/Visible.ico"
UnselectedIcon="../Resources/Images/DesignerLayers/Unvisible.ico"
ToolTip="隐藏/显示"
IsSelected="{Binding IsSymbolVisible, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridView>
<ListView.View>
在.cs代码内,如何获取这个x:Name="Eyes"的元素呢:
var listViewItem = (_listView.ItemContainerGenerator.ContainerFromIndex(i)) as ListViewItem; // i 这第i行对应的ListViewItem的索引
DesignerLayerOptionMenu textBox = listViewItem.FindVisualDescendant<DesignerLayerOptionMenu>("Eyes");
//而这个FindVisualDescendant方法是扩展方法:我在stackoverflow社区找到的其一贴子的代码
/// <summary>
/// stackoverflow:
/// http://stackoverflow.com/questions/1298274/c-wpf-get-binding-path-of-an-element-in-a-datatemplate
/// </summary>
public static class ControlAux
{
static public IEnumerable<T> GetVisualDescendants<T>(this DependencyObject item) where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(item); ++i)
{
DependencyObject child = VisualTreeHelper.GetChild(item, i);
if (typeof(T) == (child.GetType()))
{
yield return (T)child;
}
foreach (T descendant in GetVisualDescendants<T>(child))
{
yield return descendant;
}
}
}
static public T FindVisualDescendant<T>(this DependencyObject item, string descendantName) where T : DependencyObject
{
return
GetVisualDescendants<T>(item).Where(
descendant =>
{
var frameworkElement = descendant as FrameworkElement;
return frameworkElement != null && frameworkElement.Name == descendantName;
}).
FirstOrDefault();
}
}