WCF的ReactiveUI命令导致更新Observable属性时出现线程错误
问题描述:
我正在尝试使用ReactiveUI命令进行WCF调用并使用ObservableAsPropertyHelper捕获结果字符串。下面我收到以下错误消息的代码 -WCF的ReactiveUI命令导致更新Observable属性时出现线程错误
WCF调用的回报,但在访问ObservableForProperty错误“调用线程不能因为不同的线程拥有它访问这个对象” - 消息和/或当提高其PropertyChanged
让我知道是否有人需要其他细节/代码。
视图模型:UserService.Authenticate是
public class LoginViewModel : ReactiveObject, IRoutableViewModel
{
public LoginViewModel(IScreen hostScreen , MainViewModel appRootViewModel, IUserService userService)
{
HostScreen = hostScreen;
UserService = userService;
Application = appRootViewModel;
var canLogin = this.WhenAny(x => x.LoginName, x => x.Password, (l, p) =>
!String.IsNullOrWhiteSpace(l.Value) && !String.IsNullOrWhiteSpace(p.Value));
LoginCommand = new ReactiveCommand(canLogin);
var loggedIn = LoginCommand.RegisterAsync(_ => Observable.Start(() =>
{
var request = new Request
{
UserIdentity = new User.Identity
{
Login = LoginName,
Password = new User.Password { Old = Password }
}
};
var authenticationResult = UserService.Authenticate(request).Authenticated;
return authenticationResult ? "Login Succeeded...Continuing"
: "Login Failed...Please try again";
}));
loggedIn.Subscribe(s =>
{
if (s == "Login Succeeded...Continuing to Analytics")
{
HostScreen.Router.Navigate.Execute(Application);
}
});
message = new ObservableAsPropertyHelper<string>(loggedIn,
s =>
{
raisePropertyChanged("Message");
});
视图代码后面到WCF端点代理电话:
public partial class LoginView : IViewFor<LoginViewModel>
{
public LoginView()
{
InitializeComponent();
this.WhenAnyValue(x => x.ViewModel).BindTo(this, x => x.DataContext);
this.Bind(ViewModel, model => model.Password, x => x.password.Text);
this.Bind(ViewModel, model => model.LoginName, view => view.userName.Text);
this.OneWayBind(ViewModel, model => model.Message, x => x.message.Content);
this.OneWayBind(ViewModel, x => x.LoginCommand, x => x.login.Command);
}
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.Register("ViewModel", typeof(LoginViewModel), typeof(LoginView), new PropertyMetadata(null));
object IViewFor.ViewModel
{
get { return ViewModel; }
set { ViewModel = (LoginViewModel)value; }
}
public LoginViewModel ViewModel
{
get
{
return (LoginViewModel)GetValue(ViewModelProperty);
}
set
{
SetValue(ViewModelProperty,
value);
}
}
}
}
答
更新:通过告诉观察者回调在当前同步上下文上运行。
.ObserveOn(SynchronizationContext.Current)
所以下面是LoginCommand可观察代码来解决上述问题。最后一行是编辑。
var loggedIn = LoginCommand.RegisterAsync(_ => Observable.Start(() =>
{
Session<NullT> init = new Session<NullT>
{
SqlKey = System.Configuration.ConfigurationManager.AppSettings["sharedKey"].ToString()
};
var initResponse = UserService.Initialize(init);
var authenticationResult = false;
if (initResponse.SessionOk)
{
initResponse.UserIdentity = new User.Identity
{
Login = LoginName,
Password = new User.Password { Old = Password }
};
authenticationResult = UserService.Authenticate(initResponse).Authenticated;
return authenticationResult ? "Login Succeeded"
: "Login Failed...Please try again";
}
else return "Failed to Initialize.";
}).ObserveOn(SynchronizationContext.Current));
答
大部分代码是正确的(除了您设置的地方message
,只需使用loggedIn.ToProperty
),但我记得,WCF试图通过摆脱SynchronizationContexts“帮助你”,你需要禁用这个(我不知道如何做到这一点虽然)
我添加[ServiceBehavior(UseSynchronizationContext = FALSE)] [CallbackBehavior(UseSynchronizationContext = FALSE)]我的服务类,但这并没有帮助 - 在它给我相同的结果。需要注意的是,当我使用方法存根替换验证呼叫时,这是有效的 - 所以保罗你是正确的,因为它与WCF有关 – denmerc
您对ToProperty的建议是否与常规属性一起工作还是需要支持域需要成为一个ObservableAsPropertyHelper消息它工作?在第一遍时,即使设置初始值参数像这样 - > loggedIn.ToProperty(this,x => x.Message,string.Empty); –
denmerc
另一个观察是如果成功验证并路由到MainView - 我得到{“调用线程必须是STA,因为许多UI组件需要这个。”}不知何故,我因为WCF而被抛出当前上下文 - 我是否留下来在LoginView上或导航到另一个视图? – denmerc