|
1. Button 在WP7中似乎没有实现ICommand接口,为MVVM开发带来了一定的麻烦。 那么我怎么办呢? 而微软System.Windows.Interactivity.dll 中的EventTrigger似乎有问题,我不知道网上很多用这个MVVMLight 是怎么实现没有抱错的。。。。。
WP7,Silverlight开发会涉及到很多的线程问题,而一般的开发很难控制线程之间出错异常的捕捉,线程及资源的释放。Reactive (Rx) 似乎是这方面天生的料。 所以我项目用到了MVVM框架ReactiveUI。大家可以在https://github.com/xpaulbettsx/ReactiveUI 这里找到。闲话不多说了。 怎么做Button的命令绑定呢? 既然无路可走,那么我们就自己修路吧,实现ICommand的Button。上菜:
View Code
public class CommandButton : Button
{
#region Command Property
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public static readonly DependencyProperty CommandProperty=
DependencyProperty.Register("Command",
typeof(ICommand),
typeof(CommandButton),
new PropertyMetadata(OnCommandChanged));
private static void OnCommandChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
((CommandButton)obj).OnCommandChanged(e);
}
private void OnCommandChanged(DependencyPropertyChangedEventArgs e)
{
if (e.OldValue != null)
{
ICommand command = e.OldValue as ICommand;
if (command != null)
{
command.CanExecuteChanged -= CommandCanExecuteChanged;
}
}
if (e.NewValue != null)
{
ICommand command = e.NewValue as ICommand;
if (command != null)
{
command.CanExecuteChanged += CommandCanExecuteChanged;
}
}
UpdateIsEnabled();
}
#endregion
#region CommandParameter Property
public object CommandParameter
{
get { return (object)GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register("CommandParameter",
typeof(object),
typeof(CommandButton),
new PropertyMetadata(OnCommandParameterChanged));
private static void OnCommandParameterChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
((CommandButton)obj).UpdateIsEnabled();
}
#endregion
private void CommandCanExecuteChanged(object sender, EventArgs e)
{
UpdateIsEnabled();
}
private void UpdateIsEnabled()
{
IsEnabled = Command != null ? Command.CanExecute(CommandParameter) : false;
}
protected override void OnClick()
{
base.OnClick();
if (Command != null)
{
Command.Execute(CommandParameter);
}
}
}
在给大家看看一个人员ViewModel 吧
View Code
///
/// this view model include user information.
///
public abstract class AccountViewModelBase : ViewModelBase
{
private string _UserId;
///
/// User's account id
///
public string UserId
{
get { return _UserId; }
set { this.RaiseAndSetIfChanged(x => x.UserId, ref _UserId, value); }
}
//private User _CurrentUser;
//protected ObservableAsPropertyHelper _CurrentUser;
private User _user;
public User CurrentUser
{
get
{
//if (_user != null)
return _user;
//return _CurrentUser.Value;
}
set { this.RaiseAndSetIfChanged(x => x.CurrentUser, ref _user, value); }
}
public ReactiveAsyncCommand GetUserCommand { get; private set; }
public AccountViewModelBase(User user = null)
{
if (user != null)
{
_user = user;
_UserId = user.Id;
}
GetUserCommand = new ReactiveAsyncCommand();
this.ObservableForProperty(x => x.UserId)
.Throttle(TimeSpan.FromMilliseconds(500))
.Subscribe(x =>
{
_user = null;// if UserId change clear the loacl user.
GetUserCommand.Execute(x.Value);
});
GetUserCommand.Subscribe(x =>
OAuthHelper.CreateClient(OAuthHelper.USER_PROFILE_URL, new ParameterCollection { new Parameter("id", (string)x) })
.GetResponseText()
.Select(s => XElement.Parse(s))
.Select(xl => xl.ReadUserInfo())
.ObserveOn(RxApp.DeferredScheduler)
.Subscribe(
u => CurrentUser = u,
ex => { this.Log().Error(ex.ToString()); MessageBox.Show(ex.ToString()); }));
}
}
这里只要UserId 的值变化,就能重新查询获得新的CurrentUser对象。 而且UserId是根据500微妙中变化的最后一个值为准来查询。
上面我的ViewModel可以更具值变化来触发GetUserCommand命令,所有可以不用绑定, 若果需要在Xaml上来触发呢,看看XMAL文件只需要这么绑定就好
好了,时间差不多了,。。List列表的绑定需要用到RelativeSource Binding,Silverlight4 和 WP7都没有实现,
下一节我们再说说怎么自定义实现RelativeSource Binding吧休息。。。。 |
|
|