如何在wpf viewmodell中访问View中的控件

【WP开发】再谈View与ViewModel之间的解耦实现方式 - * { float: } - ITeye技术网站
博客分类:
MVVM模式的View与ViewModel的三大通讯方式:Binding Data(实现数据的传递)、Command(实现操作的调用)和Attached Behavior(实现控件加载过程中的操作)。
这里再谈一下textbox双向绑定的问题以及绑定行为的一些东西。
一、textbox双向绑定取值异常问题:
就比如说这个textbox:
&TextBox Text="{Binding Mobile,
Mode=TwoWay}"
BorderBrush="{StaticResource PhoneAccentBrush}"
Background="{StaticResource PhoneBackgroundBrush}"/&
很明显是个双向绑定的数据模式,我们在看后端vm代码
public void SubmitAction()
if (!this.ValidateData())
App.LwApi.GetInternalService().BindMobile(this.Mobile, this.Code, (o, ev) =&
if (ev.Error != null)
MessageHandleHelper.HandleError(ev.Error);
MessageBox.Show("手机号绑定成功!");
NavigationController.GoBack();
上述代码在提交命令触发时调用,这里有一个很奇怪的现象:当我们直接触发点击事件时,是无法同步的享有Mobile属性的值的,只有在用户再对textbox失焦后才能正常的。
这里的原因在于wp系统只在当前textbox触发LostFocus事件后才会对绑定的数据赋值。现在我们就需要将事件触发提前到每一次的TextChanged事件里进行触发。
将代码改成:
&TextBox Text="{Binding Mobile,
Mode=TwoWay, UpdateSourceTrigger=Explicit}" TextChanged="OnPhoneTextBoxTextChanged"
BorderBrush="{StaticResource PhoneAccentBrush}"
Background="{StaticResource PhoneBackgroundBrush}"/&
注意上面的 UpdateSourceTrigger 属性:TwoWay是由绑定目标到绑定源方向,若实现绑定目标的值更改影响绑定源的值方式,只需要设置相应控件绑定时的UpdateSourceTrigger的值,其值有三种:1、PropertyChanged:当绑定目标属性更改时,立即更新绑定源。2、 LostFocus:当绑定目标元素失去焦点时,更新绑定源。3、 Explicit:仅在调用 UpdateSource 方法时更新绑定源。 多数依赖项属性的UpdateSourceTrigger 值的默认值为 PropertyChanged,而 TextBox 属性的默认值为 LostFocus。
我们现在把它设置为Explicit的意思就是要在cs文件里手动调用UpdateSource 方法才会更新绑定源数据。cs代码如下:
private void OnPhoneTextBoxTextChanged(object sender, TextChangedEventArgs e)
TextBox ptb = sender as TextB
BindingExpression be = ptb.GetBindingExpression(TextBox.TextProperty);
be.UpdateSource();
上面的代码就是手动调用更新绑定源的操作。
现在我们可以看到viewmodel层已经可以正确的操作属性了。
下面我们再看一下附加行为方式的解耦:
二、LongListSelector的回到顶部功能的Attached Behavior方式实现
回到顶部的功能其实在codebehind代码里写起来异常的简单:只需一句ScrollTo就能轻松搞定,但我们的业务代码全部写在Viewmodel中,比如我们执行了refreshData的操作,要求list回到顶部,如果ScrollTo写在cb代码里,我们就必须要用notification方式去实现,然而这种方式既会搞得代码很复杂而且后期维护的成本也很大。(不要问我那为什么要把业务代码写vm里。。。vm里写业务代码能使得前端UI修改方便,而且移植起来也方便,甚至我们的win8 app就直接能套用wp的业务vm代码)
为了使这里我们要用到第三种解耦模式:Attached Behavior方式也就是行为依赖的方式。我们会写一个ToTop的Behavior类。这里先看它的调用方式:
&toolkit:LongListSelector x:Name="StoryListBox" Background="Transparent"
ShowListHeader="False" ShowListFooter="False" IsFlatList="True" BufferSize="5.0"
lwcontrols:ToTopBehavior.GoTop="{Binding GoTopFlag, Mode=TwoWay}"
ItemsSource="{Binding StoryList}" ItemTemplate="{StaticResource StoryTemplate}"
看到这一句: lwcontrols:ToTopBehavior.GoTop="{Binding GoTopFlag, Mode=TwoWay}"这个就是Behavior的xml绑定方式;
再来看vm:
private bool goTopF
public bool GoTopFlag
get { return goTopF }
goTopFlag =
this.RaisePropertyChanged("GoTopFlag");
public override void RefreshData(Action&object& callback = null)
base.RefreshData((o) =&
GoTopFlag =
callback.Invoke(o);
是的,我们需要一个双向绑定的属性,在vm中直接调用 GoTopFlag =就能使list直接回到顶部;看是如何做到的(ToTopBehavior.cs):
namespace Laiwang.Controls
static public class ToTopBehavior
public static readonly DependencyProperty GoTopProperty = DependencyProperty.RegisterAttached(
typeof(bool),
typeof(ToTopBehavior),
new PropertyMetadata(new PropertyChangedCallback(OnGoTopChanged)));
public static bool GetGoTop(DependencyObject obj)
return (bool)obj.GetValue(GoTopProperty);
public static void SetGoTop(DependencyObject obj, bool value)
obj.SetValue(GoTopProperty, value);
private static void OnGoTopChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
LongListSelector control = obj as LongListS
if (control != null)
if ((bool)args.NewValue)
ScrollViewer scrollViewer = CommonHelper.FindChildOfType&ScrollViewer&(control);
if (scrollViewer.VerticalOffset & 1)
object o =
foreach (var item in control.ItemsSource)
if (item == null)
control.ScrollTo(o);
SetGoTop(control, false);
像给依赖对象附加依赖属性一样,我们这里只是对一个已有的依赖对象附加一个新的依赖属性:GoTop,我们所有的操作都是在OnGoTopChanged事件做的,事实上我们这个方法是对双向模式中的PropertyChangedCallback,还记得一般的双向的UpdateSourceTrigger都是PropertyChanged吗,对于依赖属性也是这样的。我们只是简单的判断了 if ((bool)args.NewValue)并作出回滚的实现,注意后面我们又调用了SetGoTop(control, false),这样做很明显就是让它下一次的赋值为true时能执行刚才的代理事件。
vm和view的解耦虽说感觉是简单的事情复杂化了,但不管怎么说,这样做的好处也显而易见的,维护的成本降低了,wp和win8的移植也变的如此的简单美妙,只需对view层更改及简单的vm更改就能轻松搞定,ms这一套wpf的东西还是非常值得借鉴的。嗯,wp8我还是非常期待啊。。。
另外,近些天一直在做的ios开发对于事件的绑定及回调都是用delegate去做,感觉非常的麻烦。试图改变这种情况,貌似ios中KVO以及block的使用会改进这些,待我研究研究。。。
浏览: 116557 次
来自: 杭州
seajs 2.1.1不支持相互依赖了。
博主,你好!可以给个完整的Demo学习一下么,谢谢!!
感谢楼主分享,看明白了 什么符合索引起作用什么符合索引不起作用 ...
以前花大力气按照amazon的方式自己写了一套
这么好的帖子竟然没人回复用Model-View-ViewModel构建iOS App
MVC是构建iOS app的标准模式。本文中,我们将重温一下MVC是什么,详述它的缺点,并且告诉你一个新的方式来架构你的app:Model-View-ViewModel。
(via:,翻译自)
如果你已经开发一段时间的iOS应用,你一定听说过Model-View-Controller,即MVC。MVC是构建iOS App的标准模式。然而,最近我已经越来越厌倦MVC的一些缺点。在本文,我将重温一下MVC是什么,详述它的缺点,并且告诉你一个新的方式来架构你的App:Model-View-ViewModel。拿出你的流行语bingo card(宾果卡,一种游戏卡片-译者注),因为我们即将进行一次范式转变。
Model-View-Controller
Model-View-Controller是一个用来组织代码的权威范式。Apple甚至是。在MVC下,所有的对象被归类为一个model,一个view,或一个controller。Model持有数据,View显示与用户交互的界面,而View Controller调解Model和View之间的交互。
在上图中,view将用户交互通知给controller。view controller通过更新model来反应状态的改变。model(通常使用Key-Value-Observation)通知controller来更新他们负责的view。大多数iOS应用程序的代码使用这种方式来组织。
模型model的对象通常非常非常的简单。很多时候,他们就是Core Data ,或者避免使用Core Data,就是其他。根据Apple的文档,model包括数据和操作数据的业务逻辑。在实践中,model层往往非常薄,不管怎样,model层的业务逻辑被拖入了controller。
视图view通常是UIKit控件(component,这里根据习惯译为控件)或者编码定义的UIKit控件的集合。进入.xib或者Storyboard会发现一个app、Button、Label都是由这些可视化的和可交互的控件组成。你懂的。View不应该直接引用model,并且仅仅通过IBAction事件引用controller。业务逻辑很明显不归入view,视图本身没有任何业务。
还有控制器controller。Controller是app的&胶水代码&:协调模型和视图之间的所有交互。控制器负责管理他们所拥有的视图的视图层次结构,还要响应视图的loading、appearing、disappearing等等,同时往往也会充满我们不愿暴露的model的模型逻辑以及不愿暴露给视图的业务逻辑。这引出了第一个关于MVC的问题...
厚重的View Controller
由于大量的代码被放进view controller,导致他们变的相当臃肿。在iOS中有的view controller里绵延成千上万行代码的事并不是前所未见的。这些超重app的突出情况包括:厚重的View Controller很难维护(由于其庞大的规模);包含几十个属性,使他们的状态难以管理;遵循许多协议(protocol),导致协议的响应代码和controller的逻辑代码混淆在一起。
厚重的view controller很难测试,不管是手动测试或是使用单元测试,因为有太多可能的状态。将代码分解成更小的多个模块通常是件好事。
遗失的网络逻辑
苹果使用的MVC的定义是这么说的:所有的对象都可以被归类为一个model,一个view,或是一个controller。就这些。那么把网络代码放哪里?和一个API通信的代码应该放在哪儿?
你可能试着把它放在model对象里,但是也会很棘手,因为网络调用应该使用异步,这样如果一个网络请求比持有它的model生命周期更长,事情将变的复杂。显然也不应该把网络代码放在view里,因此只剩下controller了。这同样是个坏主意,因为这加剧了厚重View Controller的问题。
那么应该放在那里呢?显然MVC的3大组件根本没有适合放这些代码的地方。
较差的可测试性
MVC的另一个大问题是,它不鼓励开发人员编写单元测试。由于view controller混合了视图处理逻辑和业务逻辑,分离这些成分的单元测试成了一个艰巨的任务。大多数人选择忽略这个任务,那就是不做任何测试。
定义模糊的&Manage&
之前我提到了view controller可以管理试图的层次结构;view controller有一个&view&属性,并且可以通过IBOutlet访问视图的任何子视图。当有很多outlet时这样做不易于扩展,在某种意义上,最好不要使用子视图控制器(child view controller)来帮助管理子视图(subview)。
要点在哪?验证用户输入的业务逻辑应归入controller还是model呢?
在这里有多个模糊的标准,似乎没有人能完全达成一致。貌似无论如何,view和对应的controller都紧紧的耦合在一起,总之,还是会把它们当成一个组件来对待。
Hey!现在有个点子...
Model-View-ViewModel
在理想的世界里,MVC也许工作的很好。然而,我们生活在真实的世界。既然我们已经详细说明了MVC在典型场景中的问题,那让我们看一看一个可供替换的选择:Model-View-ViewModel。
MVVM,不过不要坚持反对它。MVVM和MVC很像。它正式规范了视图和控制器紧耦合的性质,并引入新的组件。
在MVVM里,view和view controller正式联系在一起,我们把它们视为一个组件。视图view仍然不能直接引用模型model,当然controller也不能。相反,他们引用视图模型view model。
view model是一个放置用户输入验证逻辑,视图显示逻辑,发起网络请求和其他各种各样的代码的极好的地方。有一件事情不应归入view model,那就是任何视图本身的引用。view model的概念同时适用于于iOS和OS X。(换句话说,不要在view model中使用 #import UIKit.h)
由于展示逻辑(presentation logic)放在了view model中(比如model的值映射到一个格式化的字符串),视图控制器本身就会不再臃肿。当你开始使用MVVM的最好方式是,可以先将一小部分逻辑放入视图模型,然后当你逐渐习惯于使用这个范式的时候再迁移更多的逻辑到视图模型中。
使用MVVM的iOS app是高度可测试的;因为view model包含了所有的展示逻辑并且不会引用view,所以它可以通过编程方式充分测试。虽然有测试Core Data模型,但使用MVVM写的app可以进行充分的单元测试。
以我的经验,使用MVVM会轻微的增加代码量,但总体上减少了代码的复杂性。这是一个划算的交易。
回过头再来看MVVM的图示,你会注意到我使用了模糊的动词&notify&和&update&,而没有详细说明该怎么做。你可以使用KVO,就像MVC那样,但这很快就会变得难以管理。事实上,会是更好的方式来组织各个部分。
关于怎么结合ReactiveCocoa来使用MVVM的信息,可以阅读Colin Wheeler的或者看看我写的。你也可以阅读我的。
CocoaChina是全球最大的苹果开发中文社区,官方微信每日定时推送各种精彩的研发教程资源和工具,介绍app推广营销经验,最新企业招聘和外包信息,以及Cocos2d引擎、Cocos Studio开发工具包的最新动态及培训信息。关注微信可以第一时间了解最新产品和服务动态,微信在手,天下我有!
请搜索微信号“CocoaChina”关注我们!
关注微信 每日推荐
扫一扫 浏览移动版(MVC3)请问如何才能把controller的HTML代码以控件形式呈现在view_mvc吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0可签7级以上的吧50个
本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:583贴子:
(MVC3)请问如何才能把controller的HTML代码以控件形式呈现在view
例如我在controler设置一ViewModelViewModel.newControl = "&p&test&/p&";但在View页用View.newControl取值时变被编码以文本形式显示在View页而不是我想要的html标记.需求的原因某些控件必需在controller定义然后在view页呈现.MVC2会把字符呈现为控件的,但MVC3下被编码了,请问有新的方法可以实现吗?
相关的贴子399641252相关的图贴
大体的看了下,你需要html解码可以用@html.raw(viewbay.xx)的方法写。如果你不用razor的语法,你把
十分感谢,已经解决使用 @Html.Raw("") 得到了未被编译的HTML代码
内&&容:使用签名档&&
为兴趣而生,贴吧更懂你。&或在 viewDidLoad 方法中调用 [self presentModalViewController:myView animated:YES] 显示ModelView 失败
>>>>在 viewDidLoad 方法中调用 [self presentModalViewController:myView animated:YES] 显示ModelView 失败
在 viewDidLoad 方法中调用 [self presentModalViewController:myView animated:YES] 显示ModelView 失败
&在一个 View Controller 的 viewDidLoad 方法中调用:
[self presentModalViewController:myView animated:YES];
显示一个Model View 会失败,这是因为:
viewDidLoad is called the first time the view property of the vc is accessed - that's when loading happens. There is no guarantee that the view is in a window at that time, and presenting a modal vc on a vc whose view is not in a window does not make sense. Perhaps viewDidAppear is what you were looking for.
解决办法可以在 viewDidAppear 中调用以上方法,或者在 viewDidLoad 中:
& &&[self performSelector:@selector(doLogon) withObject:nil afterDelay:0.1];
-(void)doLogon{
& & LogonView *logon = [[LogonView alloc]initWithNibName:@&LogonView& bundle:nil];
& & logon.parent=self;
& & [self presentModalViewController:logon animated:YES];
& & [logon release];
发布日期:日
日志归类:iPhone
共有0条回复,如下
暂没有相关评论
评论内容:
华南师范大学网络教育学院
院办:020- 传真:020-Current IssueReceive the MSDN Flash e-mail newsletter every other week, with news and information personalized to your interests and areas of focus.

我要回帖

更多关于 csgo viewmodel 的文章

 

随机推荐