[翻译]Windows Phone(Silverlight) 控件数据绑定

UI效果

“图1”

 


开始

1.打开Visual Studio创建一个名为DataBinding的Windows Phone应用程序。
2.添加一个用于绑定数据的类。在“解决方案”上右键项目选择“添加->新建项->类”,命名为“Person.cs”。

Person包括以下属性,这些属性用于绑定UI视图。Person包括以一个枚举属性和其他属性。如下代码。

public class Person
{
  public enum Sex
  {
    Male,
    Female,
  }
  public string Name { get; set; }
  public bool Moustache { get; set; }
  public bool Goatee { get; set; }
  public bool Beard { get; set; }
  public Sex WhichSex { get; set; }
  public double Height { get; set; }
  public DateTime BirthDate { get; set; }
  public bool Favorite { get; set; }
}

看得出来,这些属性映射到 “图1” UI上面的控件。布尔类型的属性是用于CheckBox或RadioButton的绑定(CheckBox和RadioButton的区别在于选择的属性是否是相互排斥的)。


创建UI界面

下一步的任务是创建用于绑定数据的UI视图。可以选择Expression Blend来设计UI:右键需要编辑的XAML页面选择“在Expression Blend打开”。个人推荐在Expression Blend上面设计UI视图,在Visual Studio上面编写托管代码。

这里将布局的Grid设置为6行2列,将相关的控件拖动到适当的位置。

下面是UI视图的XAML:

XAML页面上的基本布局

 


绑定

每一个交互控件都有一个用于设置数据绑定语法的属性。例如,在TextBox的Text属性使用绑定语法。如前面的XAML所示。
绑定语法:绑定语法使用花括号“{}”,并用键盘输入“Binding”,接着输入用于绑定的属性名称。

例如,下面的XAML中的TextBox的Text属性绑定了一个叫“Name”的公共属性。

<TextBox
x:Name="Name"
TextWrapping="Wrap"
d:LayoutOverrides="Height"
Grid.Column="1"
HorizontalAlignment="Left"
Width="200"
VerticalAlignment="Center"
Text="{Binding Name}" />

同样,在CheckBox的IsChecked属性绑定需要的属性:

<CheckBox
x:Name="Moustache"
Content="Moustache"
HorizontalAlignment="Left"
VerticalAlignment="Center"
IsChecked="{Binding Moustache}" />

这个时候,你还不知道你要绑定这些属性(“Name”和“Moustache”)的对象(Object)。用于绑定的对象的属性是“DataContext”。“DataContext”可以是任何东西,但是在这里,我们绑定的是一个Person类的实例。新建一个Person类的实例对象,然后将这个对象设置到绑定UI对象的DataContext当中。
当你可以设置一个容器的DataContext。这个时候,在这个容器内的所有控件都能共享这个DataContext。你可以自由指定一个控件或多个控件的DataContext。

 


在托管代码指定绑定的实例对象

在托管代码的Loaded事件里面实例化Person类。Loaded事件在页面第一次加载和控件初始化的时候会触发。

下面是初始化Person类的代码:

private Person _currentPerson;
private Random _rand = new Random();
public MainPage()
{
  InitializeComponent();
  Loaded += MainPage_Loaded;
}
void MainPage_Loaded( object sender, RoutedEventArgs e )
{
  _currentPerson = new Person
  {
    Beard = false,
    Favorite = true,
    Goatee = false,
    Height = 1.86,
    Moustache = true,
    Name = "Jesse",
    WhichSex = Person.Sex.Male
  };
}

设置ContentPannel控件的DataContext为刚刚实例化的_currentPerson对象(在Loaded事件里面)。

ContentPanel.DataContext = _currentPerson;

当控件知道它设置了DataContext属性之后,控件就会解析的绑定。此时TextBox就会解析Text里面的绑定语法获得Name属性的值(“Jesse”)。基本上所有控件都适用,每一个控件的绑定范围都应该限定在设置DataContext的对象。
运行程序,可以看到绑定数据。

 


更改DataContext

为了表明绑定和显示之间的关系,我们创建多个Person来切换显示。修改UI界面,增加一个Name为“Next”的Button控件。可以添加在Grid里面最底下的一行。

<Button
Name="Next"
Content="Next"
Grid.Row="5"
HorizontalAlignment="Center"
VerticalAlignment="Center" />

下面是增加“Next”Button之后的托管代码。

void MainPage_Loaded( object sender, RoutedEventArgs e )
{
  SetDataContext();
  Next.Click += Next_Click;
}
private void SetDataContext()
{
  ContentPanel.DataContext = GeneratePerson();
}
void Next_Click( object sender, RoutedEventArgs e )
{
SetDataContext();
}

我们将在Loaded事件和Button的Click事件里面设置DataContext绑定对象,所以新增一个名叫“SetDataContext”的函数用于调用。为了显示修改之后的数据,增加一个名为“GeneratePerson”的方法用于产生一些随机属性的Person对象。
现在我们可以忽略生成Person数据的代码。我们已经用GerneratePerson的方法来代替手动编写Person类。

产生随机属性的Person对象
下面是完整的GerneratePerson方法。可以看出我们将产生Bool值的任务交给了FlipCoin方法。

private Person GeneratePerson()
{
var newPerson = new Person
{
Beard = FlipCoin(),
Favorite = FlipCoin(),
Goatee = FlipCoin(),
Height = _rand.NextDouble() + 1,
Moustache = FlipCoin(),
Name = names[_rand.Next(0, names.Count - 1)]
};
return newPerson;
}

private bool FlipCoin()
{
return _rand.Next( 1, 3 ) % 2 == 0;
}

最后,新建一个含六个string的list<string>泛型集合供Name随机选择。

private readonly List<string> names = new List<string>()
{
"Stacey",
"Robbie",
"Jess",
"Robin",
"Syd",
"J.J.",
"Terri",
"Moonunit",
};

运行程序并点击“Next”按钮。每次点击,Grid的DataContext属性都会被重新设置。

 


INotifyPropertyChanged

当Person对象的某个属性发生变化的时候会发生什么事情呢?当其他用户对同一个对象或数据发生修改时,程序就需要在UI上面更新数据。
此时,我们需要将保存数据的类(例如Person)实现INotifyPropertyChanged接口。INotifyPropertyChanged接口在属性值发生修改的时候会通知UI做出修改。通常的做法是新建一个helper方法进行检查,确保事件能够被注册。这样的话,Helper方法会触发该事件,传递属性名称,更新UI。

实现:

增加一个叫“Change”的按钮。当按钮被点击的时候,改变_currentPerson对象的Name的值。

void Change_Click( object sender, RoutedEventArgs e )
{
_currentPerson.Name = "Jacob";
}

如果Person没有实现INotifyPropertyChanged接口,Name属性发生变化的时候不会触发PropertyChanged时间,UI界面也不会发生数据的变化。

public class Person : INotifyPropertyChanged
{
  public string _name;
  public string Name
  {
    get { return _name; }
    set
    {
      _name = value;
      PropChanged( "Name" );
    }
  }
  // Other properties
  public event PropertyChangedEventHandler PropertyChanged;
  private void PropChanged(string propName)
  {
    if (PropertyChanged != null)
    {
      PropertyChanged( this, new PropertyChangedEventArgs( propName ) );
    }
  }
}

用INotifyPropertyChanged接口,就可以在属性发生变化的时候更新UI上面的变化。

 


Two-Way Binding

当用户跟UI进行交互的时候,用户修改了控件的属性值,你希望被用于绑定的对象的值也发生相应的改变的时候,你可以使用双向绑定模式。(two-way binding)
(绑定分别有三种模式,one-way,two-way,OneTime)
修改程序中控件的绑定模式为two-way binding,例如:

<TextBox
x:Name="Name"
TextWrapping="Wrap"
d:LayoutOverrides="Height"
Grid.Column="1"
HorizontalAlignment="Left"
Width="200"
VerticalAlignment="Center"
Text="{Binding Name, Mode=TwoWay}" />

绑定语法的三种模式

    • One-time 绑定意思是数据只绑定一次,后面数据发生更新之后,UI上的数据不再改变;
    • One-way 是默认的绑定模式;意思是绑定的对象和UI只是单向的绑定,UI上的数据发生改变的时候,不会改变对象的值;
    • Two-way 绑定允许数据和UI进行双向的绑定,即任何一边的改变都会改变另外一边。

Element Binding

把“Next”按钮移动到第六行,拖动一个Slider控件到第五行。有一些用来设置Slider控件的属性,包括

    • Minimum
    • Maximum
    • Value
    • LargeChange
    • SmallChange

下面的Slider设置了相关属性,可以参考

<Slider
x:Name="Likability"
Grid.Row="5"
Grid.Column="0"
BorderBrush="White"
BorderThickness="1"
Background="White"
Foreground="Blue"
LargeChange="10"
SmallChange="1"
Minimum="0"
Width="199"
Maximum="100"
Value="50"
Height="90" />

Minimum和Maximum用来设置Slider的范围。因为要用于百分比,所以这里将Slider的范围设置为0到100。
Value是Silder当前的值,Value的范围为:Minimum <= value <= Maximum。
LargeChange和SmallChange更多的时候被用于滚轮或者键盘的箭头,这是用来调整一次“箭头”或“滚轮”跳转的值。

 


设置TextBlocks

在Slider的右侧增加三个TextBlocks,第一个和第三个用于显示固定值(分别用于显示“Likeability”和“%”)。第二个显示Silder的值。
将第二个的TextBlock的Text属性绑定为Slider的Value,键盘输入ElementName并指定Slider的Name属性

<StackPanel
x:Name="LikeabilityPercentStackPanel"
Grid.Row="5"
Grid.Column="1"
Orientation="Horizontal">
<TextBlock
Text="Likeability: "
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="20,0,5,0" />
<TextBlock
x:Name="SliderValue"
Text="{Binding Value, ElementName=Likeability, StringFormat=F3}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="5,0,0,0"/>
<TextBlock
Text="%"
HorizontalAlignment="Left"
VerticalAlignment="Center" />
</StackPanel>

运行程序并移动Slider,可以看到TextBlock的值会发生实时的改变。

 


Data Converters

有些时候,一些属性无法直接绑定到UI控件上面。或者,有时候,你希望对控件的绑定值有更高的控制权。

以上方法可以解决大多数时候的绑定,但是免不了我们的UI需要显示的结果和我们绑定的类的数据不一定是一致的。譬如,类内存储性别可能用的是一个Boolean类型,但是显示的时候我们可能要显示“男/女”。“Data Converter”就是被设计出来处理这种类似的问题的。例如,我们用类的Model可能是出生日期,但是我们要显示Person的年龄。这个时候“Data Converter”就有用武之地了。

下面是个简单的例子,目的是显示用户的出生日期

在MainPage.xaml.cs里面修改GeneratePerson方法,新建一个BirthDate字段。BirthDate的值限定在近20年内随机的一天。

BirthDate = DateTime.Now - TimeSpan.FromDays(_rand.Next(1,365*20)),

如果你直接绑定BirthDate属性,UI会直接显示出生的日期和时间。但是我们其实只是需要显示日期而已,不需要显示时分秒那么具体的时间。这时候我们采用“DataConverter”来实现我们的功能。

DataConverters的类必须实现IValueConverter接口。这个接口有必须实现的方法。
如下代码:
IValueConverter接口的两个方法

public object Convert(
object value,
Type targetType,
object parameter,
System.Globalization.CultureInfo culture )
{
  throw new NotImplementedException();
}
public object ConvertBack(
object value,
Type targetType,
object parameter,
System.Globalization.CultureInfo culture )
{
  throw new NotImplementedException();
}

但是在这个我们只需要第一个方法(第二个方法在这里没有用处)。实现Convert的代码非常简单。

首先,保证转换之后的数据类型(tergetType)是一个字符串,传入的值(value)的类型是一个DateTime。然后,将value转化成DateTime类型并调用ToShortDateString方法。
以下是代码:

public object Convert(
object value,
Type targetType,
object parameter,
System.Globalization.CultureInfo culture )
{
if (targetType == typeof( string ) &&
value.GetType() == typeof( DateTime ))
{
return (( DateTime ) value).ToShortDateString();
}
else // Unable to convert
{
return value;
}
}
public object ConvertBack(
object value,
Type targetType,
object parameter,
System.Globalization.CultureInfo culture )
{
throw new NotImplementedException();
}

在XAML调用Converter首先得先引用,保证XAML能够访问地到Converter。将Converter设置为资源。打开“App.xaml”

*.在它的命名空间里面添加上converter所在的控件。譬如这里是这样添加的:

xmlns:mine="clr-namespace:DataBinding"

*.然后找到<Application.Resource>节点,将converter添加上。

<Application.Resources>
<mine:DateConverter x:Key="dateConverter" />
</Application.Resources>

*.在需要显示的地方用如下绑定语法:

<TextBlock
Grid.Row="6"
Grid.Column="1"
VerticalAlignment="Center"
Text="{Binding BirthDate, Converter={StaticResource dateConverter}}" />

运行程序,就可以看到BirthDate的格式变成了短时间格式。即,只有日期没有时分秒的时间。

 


Powerful Applications

(最后一段不翻译)“Data binding allows you to create powerful Windows Phone applications that reliably manage the relationship between underlying data and the controls and views that display that data. In this article you saw how to create simple data binding and two-way data binding, how to bind to elements and how to use data converters to massage the data into the format you want.”

 

时间: 2024-10-21 09:21:57

[翻译]Windows Phone(Silverlight) 控件数据绑定的相关文章

背水一战 Windows 10 (50) - 控件(集合类): ItemsControl - 基础知识, 数据绑定, ItemsPresenter, GridViewItemPresenter, ListViewItemPresenter

原文:背水一战 Windows 10 (50) - 控件(集合类): ItemsControl - 基础知识, 数据绑定, ItemsPresenter, GridViewItemPresenter, ListViewItemPresenter [源码下载] 背水一战 Windows 10 (50) - 控件(集合类): ItemsControl - 基础知识, 数据绑定, ItemsPresenter, GridViewItemPresenter, ListViewItemPresenter

数据绑定 richtextbox-C# Richtextbox控件数据绑定之后,无法正常输入

问题描述 C# Richtextbox控件数据绑定之后,无法正常输入 最近在做winform系统时候遇到一个问题,百思不得其解,希望高手可以帮忙解决一下. 如下所示,有一个richtextbox控件,name是rtbZLBB, 后台有一个类, 是ZLBB,现在将richtextbox绑定到ZLBB对象上,但是在输入内容到richtextbox控件的时候,发现无法正常的追加输入,每一次输入光标都是停留在最前面,请问高手这是为什么?进过分析,把Content属性换成private或protected

背水一战 Windows 10 (52) - 控件(集合类): ItemsControl - 自定义 ItemsControl, 自定义 ContentPresenter

原文:背水一战 Windows 10 (52) - 控件(集合类): ItemsControl - 自定义 ItemsControl, 自定义 ContentPresenter [源码下载] 背水一战 Windows 10 (52) - 控件(集合类): ItemsControl - 自定义 ItemsControl, 自定义 ContentPresenter 作者:webabcd 介绍背水一战 Windows 10 之 控件(集合类 - ItemsControl) 自定义 ItemsContr

如何为IDE注册第三方Silverlight控件

为IDE注册第三方Silverlight控件,相对WinForm平台下第三方控件的注册,较为复杂.这里结合实际,给出一个相对方便的解决方案,欢迎讨论.   先看结果,以InputMan for Silverlight(简称IMSL)产品为例,注册好了以后如下图,在Choose Toolbox Items对话框直接Filter就可以找到到IMSL的控件了:     这样,从Toolbox拖一个IMSL控件以后工程就可以自动正确的把IMSL的两个Assembly都加到工程里了.   方法: 将下面的

用 Windows 窗体 DataGrid 控件验证输入

datagrid|window|控件 Windows 窗体 DataGrid 控件验证输入 Windows 窗体 DataGrid 控件有两种可用的输入验证类型.如果用户试图输入一个值,而该值具有单元格不可接受的数据类型(例如,向需要整数的单元格中输入一个字符串),则新的无效值将替换为旧值.这种输入验证是自动完成的,不能进行自定义. 另一种的输入验证可用于拒绝任何不可接受的数据,例如,在必须大于或等于 1 的字段中输入 0,或者一个不合适的字符串.这是在数据集中通过编写 DataTable.Co

玩转Silverlight控件(一)——开篇

在园子里已经有了好多关于Silverlight的文章,在这里我就不再滥竽充数放到首页了,就随便的一篇 篇来写吧,希望能给需要的人带来帮助. 希望大家关注. 给出Silverlight 2的安装: 下载:http://www.microsoft.com/silverlight/resources/install.aspx 接下来,请确保您的Visual Studio 2008的版本是sp1,下载: http://www.microsoft.com/DownLoads/details.aspx?fa

Silverlight控件注册验证机制探索

先给大家介绍一下Silverlight客户端控件的使用情景.一般来说, Silverlight客户端控件会销售给开发Silverlight程序的公司,他们是控件的购 买者.他们开发的程序中会用到Silverlight客户端控件.但是Silverlight控件 最终是在浏览Silverlight 程序的网站用户机器上执行的.说的有点绕,请参照 下图. 这个纯客户端注册验证机制主要流程如下: 1,控件购买者下载使用Silverlight控件(Silverlight控件中包含 PublicKey及验证

WinCE 4.2下轻松调用Windows Media Player控件

小弟是个刚入门的菜鸟,现在大家都在做嵌入式开发了,所以我也来凑凑热闹.菜鸟就是菜鸟,这不,现在想在 WinCE4.2 下播放 wma.mp3 音乐,可是连个 Winodws Media Player 控件都不知道该怎么调用.大家可不要笑啊,以前我在 Winodws2000 平台下,感觉调用这个控件非常简单,可是在 WinCE4.2 平台下就没辙了.为什么呢?原因就是基于 WinCE4.2 平台的程序开发要在 Windows2000 等平台上做,可是在 Windows2000 平台上调出来的 Wi

视频-c#的windows media player控件为什么获取当前进度和总长度总是0?

问题描述 c#的windows media player控件为什么获取当前进度和总长度总是0? string str1 = axWindowsMediaPlayer1.Ctlcontrols.currentPosition.ToString(); string str2 = axWindowsMediaPlayer1.currentMedia.duration.ToString(); 我是在button1的click事件里写的,button1是打开视频的按钮,结果是"0",为什么?视频

背水一战 Windows 10 (62) - 控件(媒体类): InkCanvas 保存和加载, 手写识别

原文:背水一战 Windows 10 (62) - 控件(媒体类): InkCanvas 保存和加载, 手写识别 [源码下载] 背水一战 Windows 10 (62) - 控件(媒体类): InkCanvas 保存和加载, 手写识别 作者:webabcd 介绍背水一战 Windows 10 之 控件(媒体类) InkCanvas 保存和加载 InkCanvas 手写识别 示例1.演示 InkCanvas 涂鸦板的保存和加载Controls/MediaControl/InkCanvasDemo3