欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Windows phone 7之数据绑定(Data Bindings)

程序员文章站 2022-04-11 15:01:15
做过asp.net或者silverlight的童鞋对数据绑定比较熟悉,wp7是基于silverlight的,silverlight for windows phone页面也是使用xaml,所以页面渲...
做过asp.net或者silverlight的童鞋对数据绑定比较熟悉,wp7是基于silverlight的,silverlight for windows phone页面也是使用xaml,所以页面渲染的原理是一样的。
数据绑定分为源(source)和目标(target),source一般分为两种,其他控件的数据源,或者数据对象。
先说说以控件作为数据源的吧,最简单的格式是:目标控件属性="{binding elementname=源控件名, path=源控件属性}"。
为了便于一会介绍converter,我放弃使用textbox作为数据源,转而使用silvder,免得一会有童鞋挑错。
在页面中放置一个silder和一个textblock,xaml代码如下
slider height="84" horizontalalignment="right" margin="0,41,0,0" name="mysilder" value="20" minimum="0" maximum="100" verticalalignment="top" width="450" />
<textblock height="30" horizontalalignment="left" margin="30,163,0,0" name="targettb" text="{binding elementname=mysilder, path=value}" verticalalignment="top" />
看到代码中,textblock的text属性的值使用了绑定,绑定的源是silder,绑定的属性是value,意思是,textblock的text属性的值,来源于silider的value属性的值
运行程序,行拖动silder,效果如下

Windows phone 7之数据绑定(Data Bindings)


看到,拖动silder时,textblock的text值也会跟着变化,这个binding的绑定模式mode有关,binding默认的mode是oneway,单项绑定,也就是说silder的value变化时,textblock的text也会变,但是textblock的text变化时silder的value不会跟着变,还有两种叫做onetime和twoway,onetime是绑定依次,也就是textblock的text获取silder的value的第一个值,当silder的value再次变化时,textblock的text不会变。twoway是双向绑定,也就是说改变silder的value,textblock的text跟着变,改变textblock的text,silder的value也会跟着变。例子在converter的效果中一起看,暂时不给了。
converter的作用是数据转换,比如我想要源的数据,但是源的数据格式又不是我想要的,那么我就可以使用converter来获取我要真正显示的值,converter改变的只是页面显示出来的值,不贵改变源数据的值。
实现converter的的方式是定义一个继承自ivalueconverter接口,并实现convert和convertback方法,现在我们在项目中添加一个类,代码如下
public class valueconverter : ivalueconverter
    {
        public object convert(object value, type targettype, object parameter, cultureinfo culture)
        {
            string strvalue = "";
            double doublevalue = (double)value;
            if (doublevalue > 50)
                strvalue = "获取的值比较大";
            else
                strvalue = "获取的值比较小";
            return strvalue;
        }
        public object convertback(object value, type targettype, object parameter, cultureinfo culture)
        {
            return value;
        }
    }
然后还要将该类添加到静态资源中,以便使用,在app.xaml中添加当前项目中的命名空间:xmlns:local="clr-namespace:databindings"
然后将valueconverter类声明为静态资源:<local:valueconverter x:key="valueconverter" />
现在修改mainpage.xaml中的textblock的text的内容:<textblock height="30" horizontalalignment="left" margin="30,163,0,0" name="targettb" text="{binding elementname=mysilder, path=value, mode=twoway, converter={staticresource valueconverter}}" verticalalignment="top" />。
上面已经将binding的mode设置成了twoway,所以我们用代码修改textblock的text属性的值,看看silder是否跟着变化。
在page_loaded方式中添加一句代码,用来在页面初始化后修改textblock的text属性的值:targettb.text = "40";
运行项目,效果如下

 Windows phone 7之数据绑定(Data Bindings)
我没在page_loaded方法中设置了textblock的text值为40,看到silder的值变成了40,证明mode=twoway起作用了,看到,textblock的text值显示的不是40,而是"获取的值比较小",证明我们的valueconverter起作用了,那么拖动silder,使他的值大于50%,我们应该猜到textblock的text值,应该是"获取的值比较大",看看效果是不是
Windows phone 7之数据绑定(Data Bindings)
接下来我们说说,实际开发中使用更多的,使用数据对象作为数据源
 
先添加一个用于提供数据源的类datasource和person,代码如下
public class datasource
    {
        private person _persondata;
        public person persondata
        {
            get
            {
                return _persondata;
            }
            set
            {
                _persondata = value;
            }
        }
        public datasource()
        {
            persondata = new person()
            {
                name = "dhc",
                sex = "男",
                age = 27
            };
        }
    }
    public class person: inotifypropertychanged
    {
        private string _name;
        public string name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
            }
        }
        private string _sex;
        public string sex
        {
            get
            {
                return _sex;
            }
            set
            {
                _sex = value;
            }
        }
        private int _age;
        public int age
        {
            get
            {
                return _age;
            }
            set
            {
                _age = value;
            }
        }
    }
 然后为mainpage页面设置数据源
datasource ds = new datasource();
datacontext = ds.persondata;
在mainpage.xaml页面中添加三个textblock,并绑定数据
<textblock text="{binding name}"/>
<textblock text="{binding sex}"/>
<textblock text="{binding age}"/>

 运行程序,效果如下
Windows phone 7之数据绑定(Data Bindings)
上面使用datacontext,datacontext就是表示的数据内容,上面设置的整个页面的数据源,几乎任何空间都有datacontext属性,设置了这个属性,其自己的属性或者子控件的属性就可绑定数据源对象的中属性的值。因为设置了父控件的datacontext之后,其中的所有子控件的datacontext属性默认和父控件一样,除非子控件设置了自己的datacontext。
绑定格式大同小异:{binding source=数据源, path=属性名}至于mode和converter,使用方式与上面介绍控件为数据源一样。source默认为datacontext,除非不是,否则一般省略不写,path关键字一般省略,所以最简格式一般为{binding 属性名}。
那么我们改变数据看看,看看textblock的text是否改变
在页面中添加一个按钮,在点击事件中添加代码
person person = datacontext as person;
person.age = 100;
运行并点击,按钮,效果如下
Windows phone 7之数据绑定(Data Bindings)
age没有变成100,这不是我们想要的结果,这事为什么呢
 

inotifypropertychanged接口
上面的程序,点击按钮,并没有像我们想象中的那样,显示age的textblock的text没有改变,这事因为数据改变后,并没有通知ui界面,为什么silder的value改变后通知了,我们自己定义的数据没有通知呢,这是因为我们上面定义的person类没有继承inotifypropertychanged,看到这个接口的名字,就知道他是干什么的,通知属性改变,他就是干这个用的。
用法是直接继承inotifypropertychanged,利用propertychangedeventhandler添加委托,通知数据已经改变,现在修改person类
public class person: inotifypropertychanged
    {
        public event propertychangedeventhandler propertychanged;
        protected virtual void onpropertychanged(propertychangedeventargs args)
        {
            if (propertychanged != null)
                propertychanged(this, args);
        }
        private string _name;
        public string name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
                onpropertychanged(new propertychangedeventargs("name"));
            }
        }
        private string _sex;
        public string sex
        {
            get
            {
                return _sex;
            }
            set
            {
                _sex = value;
                onpropertychanged(new propertychangedeventargs("sex"));
            }
        }
        private int _age;
        public int age
        {
            get
            {
                return _age;
            }
            set
            {
                _age = value;
                onpropertychanged(new propertychangedeventargs("age"));
            }
        }
    }
再次运行程序,点击按钮,效果如下
 


Windows phone 7之数据绑定(Data Bindings)




好了,这就是我们想要的结果。
在最后补充一点东西,我们可以将数据声明为静态资源,然后也可以绑定
声明静态资源:<local:datasource x:key="data"/>
为页面设置数据源:datacontext="{staticresource data}"
为控件属性绑定数据
<textblock text="{binding persondata.name}"/>
<textblock text="{binding persondata.sex}"/>
<textblock text="{binding persondata.age}"/>
运行效果和上面是一样的。我之所以留到最后将绑定静态资源,是因为,如果不继承inotifypropertychanged接口的数据源,声明为静态资源,绑定后页面中没有数据,这事因为我们按照比较合理的方式编写datasource类,在构造函数中初始化数据,这样,等于说是声明属性时,没有赋值(为null),而在构造函数中改变数据,由于没有继承inotifypropertychanged接口,所以不会通知ui数据以改变(还是null),这就无法显示了,我们需要改写datasource,在声明persondata变量时就给他赋值,这样就能显示了,但是这是不好的写法,而且使用了get,set属性访问器,更会出问题,代码丑陋不堪,而我如果不说明,童鞋用了我现在的代码,而无法显示数据,该骂我了,所以我讲完inotifypropertychanged,在说绑定静态资源,你继承了inotifypropertychanged肯定不会出问题。



作者 董贺超