先来了解一下什么是依赖属性,先来看看这段代码,大家很熟悉,但是为什么我要让大家看呢.
<Window x:Class="WPF依赖属性.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="332" Width="501" Background="Tomato">
//这是一个静态资源,大家很熟悉
<Window.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="72*" />
<ColumnDefinition Width="206*" />
</Grid.ColumnDefinitions>
//这里使用了静态资源,为什么他能认识上面的值呢,就是因为wpf的依赖属性机制实现的.
<Button Background= "{StaticResource MyBrush}" Content="1 使用依赖属性从资源动态获取参数" Height="47" VerticalAlignment="Top" Margin="38,62,30,0" Grid.ColumnSpan="2" />
<Button Margin="38,115,30,124" Name="button1" Click="button1_Click" Grid.ColumnSpan="2">2 Get 依赖属性</Button>
<TextBox Margin="38,0,120,16" Name="textBox1" Height="23" VerticalAlignment="Bottom" Grid.ColumnSpan="2">你好</TextBox>
<Button Margin="38,0,30,86" Name="button2" Click="button2_Click" Grid.ColumnSpan="2" Height="23" VerticalAlignment="Bottom">3 Set 依赖属性</Button>
<Button Height="23" Margin="38,0,30,45" Name="button3" VerticalAlignment="Bottom" Click="button3_Click" Grid.ColumnSpan="2">4 使用属性封装依赖属性</Button>
<Label Height="45" Margin="105,11,90,0" Name="label1" VerticalAlignment="Top" FontSize="24" Grid.ColumnSpan="2">依赖属性演示 </Label>
</Grid>
</Window>
依赖属性的我们使用了很多次的资源字典的形式来写,今天我们换一种方法使用.这个是后台代码我们一点点看.
namespace WPF依赖属性
{
/// <summary>
/// Window1.xaml 的交互逻辑
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
//依赖属性今天要说的就是这些东西. 这行代码表示向wpf属性系统注册依赖属性
//前三个参数,很简单,然后就是注册的值,后面跟着一个值发生改变的回调.
private static readonly DependencyProperty myNameProperty = DependencyProperty.Register(
"myName",
typeof(string),
typeof(Window1),
new FrameworkPropertyMetadata(".NET Hello",
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnMyNamePropertyChanged)
)
);
//封装了注册的实例,便于访问.
public string MyNameProperty
{
get { return this.GetValue(Window1.myNameProperty).ToString(); }
set { SetValue(Window1.myNameProperty, value); }
}
//这是一个回调,只要注册的值发生了改变,就会弹出这个对话框.
public static void OnMyNamePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
global::System.Windows.MessageBox.Show("值发生改变了...");
}
//通过GetValue的方式拿到注册的依赖属性值
private void button1_Click(object sender, RoutedEventArgs e)
{
global::System.Windows.MessageBox.Show(this.GetValue(Window1.myNameProperty).ToString());
}
//使用SetValue对注册的依赖属性进行更改,这时候上面那个回调就会起作用了
private void button2_Click(object sender, RoutedEventArgs e)
{
this.SetValue(Window1.myNameProperty, this.textBox1.Text);
//this.MyNameProperty = this.textBox1.Text; //get set的使用,不说了
}
//通过封装的属性,来访问注册的依赖属性
private void button3_Click(object sender, RoutedEventArgs e)
{
global::System.Windows.MessageBox.Show(this.MyNameProperty);
}
}
}
下面继续了解路由事件.先看一下wpf的事件的几种工作方式.
直接方式,只有元素自身调用的事件
冒泡方式,从根元素向根节点依次响应事件
隧道方式,从根节点向根元素依次响应事件
先来看一段隧道方式的事件代码,在wpf里面所有PreviewMouseDown这种P开头的事件都是隧道事件.
<Window x:Class="绑定依赖属性路由.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid PreviewMouseDown="Grid_PreviewMouseDown">
<Button Content="Button1" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="button1" VerticalAlignment="Top" PreviewMouseDown="button1_PreviewMouseDown" Width="75" />
</Grid>
</Window>
前台就一个button按钮,grid和button都在使用同一种事件,看谁先响应.
private void Grid_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("Grid1");
//e.Handled = true; 这句话的意思是 截断事件,如果截断了事件,就不会响应button的事件了.
}
private void button1_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("button1");
}
后台就两个事件代码.其他的工作方式都是和以前一样,大家试试就知道了,只有隧道模式比较特殊.
Wpf里面还可以通过这样来添加事件.新的特性.
这是一个button的点击事件,很正常.
private void Button_Click3(object sender, RoutedEventArgs e) {
我们可以通过找到这个元素的name来添加事件. Grid.MouseDownEvent 这样就是为这个元素添加一个MouseDown事件.
grid3.AddHandler(Grid.MouseDownEvent, new RoutedEventHandler(Grid_MouseDownNext), true);
}
private void Grid_MouseDownNext(object sender, RoutedEventArgs e) {
MessageBox.Show("Grid被点击");
}
下面来了解一个比较麻烦的例子,依赖事件.
前台代码比较简单就是一个button按钮
<Window x:Class="WPF_依赖事件.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300" Loaded="Window_Loaded">
<Grid>
<Label Height="47" Margin="12,12,-7,0" Name="label1" VerticalAlignment="Top" FontSize="24">依赖事件演示</Label>
<Button Height="23" Margin="59,0,21,64" Name="button1" VerticalAlignment="Bottom" >Send</Button>
</Grid>
</Window>
后台代码比较麻烦
namespace WPF_依赖事件
{
/// <summary>
/// Window1.xaml 的交互逻辑
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
..通过这种方式来添加一个路由
this.button1.AddHandler(Button.ClickEvent, new RoutedEventHandler(C));
当然,还可以这样写
//this.button1.Click += new RoutedEventHandler(button1_Click); 直接+=
//this.button1.Click += (senders, es) => { }; 通过lambda
//this.button1.Click += delegate { }; 匿名方法
//这个事件比较是 自定义的一个事件
this.okRoutedEvent += new RoutedEventHandler(Window1_okRoutedEvent);
}
void Window1_okRoutedEvent(object sender, RoutedEventArgs e)
{
global::System.Windows.MessageBox.Show(DateTime.Now.ToString());
}
//一个静态的只读性的事件字段
private static readonly RoutedEvent okEvent = EventManager.RegisterRoutedEvent("okEvent", RoutingStrategy.Direct, typeof(RoutedEvent), typeof(RoutedEventArgs));
//我们通过一种事件属性的写法 来访问这个事件
public event RoutedEventHandler okRoutedEvent
{
add
{
AddHandler(okEvent, value);
}
remove
{
RemoveHandler(okEvent, value);
}
}
//这个是button点击的事件
public void C(object o, RoutedEventArgs e)
{
//通过button点击来发布这个事件.
RoutedEventArgs args = new RoutedEventArgs(okEvent);
this.RaiseEvent(args); //引发特定的路由事件
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
}
}
}
//总结来说,就是用 定义了一个路由事件.通过事件属性来访问, 让当前窗体使用这个事件, 然后通过 button的点击来发布这个事件,达到触发窗体 自定义的事件,非常好理解的一个逻辑.
下章全部讲解数据绑定.