WPF QuickStart数据绑定(Data Binding)
首先看一下WPF Data Binding的概览,
Binding Source可以是任意的CLR对象,或者XML文件等,Binding Target需要有依赖属性。这样便可以进行Data Binding。请看下面的示例,
C#
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = new Person() { Name = "Tom", Age = 25 }; } } public class Person { public string Name { get; set; } public int Age { get; set; } }
XAML:
<Grid> <StackPanel> <TextBlock Text="{Binding Name}" Margin="10,5"/> <TextBlock Text="{Binding Age}" Margin="10,5"/> </StackPanel> </Grid>
运行结果:
下面通过一些例子来介绍在Data Binding,
1. 我们可以在XAML中,指定Binding Target的ElementName和Path属性来获取Binding Source的数据,例如,
XAML:
<StackPanel> <Slider x:Name="_slider" Minimum="0" Maximum="100" Value="20"/> <TextBox Text="{Binding ElementName=_slider,Path=Value}"/> </StackPanel>
运行结果:
上面XAML代码中,将Slider的Value属性Binding到TextBox。
通过上面的Gif图片可以发现,当拖动Slider时,TextBox框中的数值随着Slider的Value改变而改变,当在TextBox中输入数值时,按Tab键失去焦点后,Slider的Value发生了改变。这是因为TextBox的默认Binding Mode为TwoWay,且UpdateSoureTrigger默认为LostFocus。请看下面的BindingMode示意图,
图示中有种Binding Mode,
OneWay,数据流向是从Source到Target;
TwoWay,数据可以从Source到Target,也可以从Target到Source,
OneWayToSource与OneWay相反,
OneTime,表示数据绑定发生后,数据源无论如何改变,Target中绑定的值都不会发生改变。
下面我们通过例子来演示这4种绑定
XAML:
<Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <!--OneWay Binding--> <StackPanel> <TextBlock Text="Binding Mode: OneWay"/> <Slider x:Name="_slider" Minimum="0" Maximum="100" Value="20"/> <TextBox Text="{Binding ElementName=_slider,Path=Value,Mode=OneWay}"/> </StackPanel> <!--OneTime Binding--> <StackPanel Grid.Row="1" Margin="0,20"> <TextBlock Text="Binding Mode: OneTime"/> <Slider x:Name="_slider1" Minimum="0" Maximum="100" Value="20"/> <TextBox Text="{Binding ElementName=_slider1,Path=Value,Mode=OneTime}"/> </StackPanel> <!--OneWayToSource Binding--> <!--将TextBox的FontSize默认值为12--> <StackPanel Grid.Row="2"> <TextBlock Text="Binding Mode: OneWayToSource"/> <Slider x:Name="_slider2" Minimum="0" Maximum="100" Value="20"/> <TextBox FontSize="{Binding ElementName=_slider2,Path=Value, Mode=OneWayToSource}" Text="{Binding RelativeSource={RelativeSource Self},Path=FontSize}"/> </StackPanel> <!--TwoWay Binding--> <StackPanel Grid.Row="3" Margin="0,20"> <TextBlock Text="Binding Mode: TwoWay"/> <Slider x:Name="_slider3" Minimum="0" Maximum="100" Value="20"/> <TextBox Text="{Binding ElementName=_slider3,Path=Value,Mode=TwoWay}"/> </StackPanel> </Grid>
运行结果:
在项目开发中根据实际需要选择不同的Binding Mode,如果某些数据只在程序启动时显示,后面对数据进行修改了,不需要更新,可以选择OneTime Mode;如果对数据进行实时展示,可以选择OneWay Mode;如果需要将数据的修改同步,那么我们选择TwoWay Mode。合适的绑定模式可以最优化程序的性能。
接下来看UpdateSourceTrigger,UpdateSourceTrigger有下面几种取值,
1. LostFocus, 例如TextBox失去焦点后更新Source;
2. PropertyChanged,例如当在TextBox中输入时,Source便同步更新;
3. Explict,需要显示的调用UpdateSource方法;
下面我们看Binding中另一个概念Converter;看这样一个例子,有一个文本框显示当前温度,如果温度大于35,则将文本框的前景色设置为红色,如果温度小于0,则显示为蓝色;
XAML:
<Window.Resources> <local:TemperatureToBrushCoverter Hot="35" Cold="0" x:Key="TemperatureToBrushCoverter"/> </Window.Resources> <Grid> <TextBox Text="30" Width="200" Height="25" Foreground="{Binding Path=Text,RelativeSource={RelativeSource Self}, Converter={StaticResource TemperatureToBrushCoverter}}"/> </Grid>
C#:
[ValueConversion(typeof(double),typeof(Brush))] public class TemperatureToBrushCoverter : IValueConverter { public double Hot { get; set; } public double Cold { get; set; } public TemperatureToBrushCoverter() { } public TemperatureToBrushCoverter(double hot,double cold) :this() { Hot = hot; Cold = cold; } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { double temp; Brush brush = Brushes.Black; if(Double.TryParse((string)value,out temp)) { if(temp > Hot) { brush = Brushes.Red; } else if(temp < Cold) { brush = Brushes.Blue; } } return brush; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
运行结果:
注意要在XAML中引用Converter。
最后我们看一下DataBinding中的数据验证;来看这样一个例子,将Person对象的Age绑定到一个TextBox上,并可以对Age进行修改,年龄是一个有实际意义的值,如果Age小于0或者大于120,我们均认为其为非法值,给出相应提示。请看下面的代码:
XAML:
<Grid> <TextBox Width="200" Height="25"> <TextBox.Text> <Binding Path="Age" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <local:AgeValidationRule ValidationStep="RawProposedValue"/> </Binding.ValidationRules> </Binding> </TextBox.Text> <!--Error Template--> <Validation.ErrorTemplate> <ControlTemplate> <StackPanel> <AdornedElementPlaceholder/> <TextBlock Text="{Binding [0].ErrorContent}" Foreground="Red"/> </StackPanel> </ControlTemplate> </Validation.ErrorTemplate> </TextBox> </Grid>
C#:
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = new Person() { Age = 25}; } } public class Person { public int Age { get; set; } } public class AgeValidationRule : ValidationRule { public override ValidationResult Validate(object value, CultureInfo cultureInfo) { int age; if(int.TryParse((string)value,out age)) { if(age< 0 || age > 120) { return new ValidationResult(false, "This is invalide age."); } else { return new ValidationResult(true, null); } } return new ValidationResult(false, "Please input valid age."); } }
运行结果:
WPF QuickStart 附加属性(Attached Property)
1. 附加属性使用,
WPF中对附加属性使用最多的莫过于对控件布局时设置控件的位置,例如在Canvas中有一个Rectangle, Ellipse, Button,我们需要设置它们的位置,
<Canvas> <Rectangle x:Name="_rect" Fill="LightBlue" Width="100" Height="50" Canvas.Left="200" Canvas.Top="50"/> <Ellipse Width="100" Height="100" Fill="LightCoral" Canvas.Left="150" Canvas.Top="200"/> <Button Content="I am a button" Width="100" Height="35" Canvas.Left="50" Canvas.Bottom="50"/> </Canvas>
除了在XAML中设置依赖属性外,也可以在C#代码中设置,例如:
Canvas.SetLeft(_rect, 100);
Canvas.SetTop(_rect, 50);
显示效果:
附加属性使用起来非常简单。
2. 自定义附加属性
现在有这样一个需求,需要将上面的Button,Ellipse,Rectangle旋转一定角度。我们可以这样来实现:
XAML:
<Canvas> <Rectangle x:Name="_rect" Fill="LightBlue" Width="100" Height="50" Canvas.Top="100" RenderTransformOrigin=".5,.5"> <Rectangle.RenderTransform> <RotateTransform Angle="45"/> </Rectangle.RenderTransform> </Rectangle> <Ellipse Width="150" Height="100" Fill="LightCoral" Canvas.Left="150" Canvas.Top="100" RenderTransformOrigin=".5,.5"> <Ellipse.RenderTransform> <RotateTransform Angle="60"/> </Ellipse.RenderTransform> </Ellipse> <Button Content="I am a button" Width="100" Height="35" Canvas.Left="50" Canvas.Bottom="50" RenderTransformOrigin=".5,.5"> <Button.RenderTransform> <RotateTransform Angle="160"/> </Button.RenderTransform> </Button> </Canvas>
效果如下:
细心的你已经发现上面的三段代码基本一样,而且还挺长的。我们可以使用附加属性来实现,新建一个RotationHelper类,代码如下:
using System.Windows; using System.Windows.Media; namespace UseAttachedProperty.Helper { public class RotationHelper : DependencyObject { public static double GetAngle(DependencyObject obj) { return (double)obj.GetValue(AngleProperty); } public static void SetAngle(DependencyObject obj, double value) { obj.SetValue(AngleProperty, value); } public static readonly DependencyProperty AngleProperty = DependencyProperty.RegisterAttached("AngleProperty", typeof(double), typeof(RotationHelper), new PropertyMetadata(0.0,OnAngleChanged)); private static void OnAngleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement element = d as UIElement; if(element != null) { element.RenderTransformOrigin = new Point(0.5, 0.5); element.RenderTransform = new RotateTransform((double)e.NewValue); } } } }
将RotationHelper类继承DependencyObject,这样不光Button,Ellipse,可以使用,其他继承自DependencyObject的元素均可使用。
现在在XAML中使用自定义Angle附加属性。
<Window x:Class="UseAttachedProperty.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:helper="clr-namespace:UseAttachedProperty.Helper" xmlns:local="clr-namespace:UseAttachedProperty" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Canvas> <Rectangle x:Name="_rect" Fill="LightBlue" Width="100" Height="50" Canvas.Top="100" helper:RotationHelper.Angle="45" /> <Ellipse Width="150" Height="100" Fill="LightCoral" Canvas.Left="150" Canvas.Top="100" helper:RotationHelper.Angle="60" /> <Button Content="I am a button" Width="100" Height="35" Canvas.Left="50" Canvas.Bottom="50" helper:RotationHelper.Angle="160" /> </Canvas> </Window>
此时显示效果和上面通过XAML中使用RenderTransform一样。
以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索c#
, 数据
, textbox
, 属性
, binding
data
maven quickstart、maven quickstart项目、cloudera quickstart、quickstart、quick start,以便于您获取更多的相关知识。