带有WCF的ReactiveUI命令导致更新Observable属性时发生Thread错误

时间:2014-01-31 01:22:54

标签: wcf reactiveui

我正在尝试使用ReactiveUI命令进行WCF调用,并使用ObservableAsPropertyHelper捕获结果字符串。使用下面的代码我收到以下错误消息 -

“调用线程无法访问此对象,因为其他线程拥有它”

WCF调用返回但访问ObservableForProperty时出错 - 消息和/或提升其PropertyChanged

如果有人需要其他详细信息/代码,请告诉我。

ViewModel: UserService.Authenticate是对WCF端点的代理调用

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");

            });

查看代码

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);
        }
    }

}

}

2 个答案:

答案 0 :(得分:0)

您的大多数代码都是正确的(除了您设置message的位置,只使用loggedIn.ToProperty),但我记得,WCF试图通过摆弄SynchronizationContexts来“帮助您”,您需要禁用此功能(我不知道该怎么做)

答案 1 :(得分:0)

更新:通过告诉观察者回调在当前同步上下文上运行来修复。

<强> .ObserveOn(SynchronizationContext.Current)

以下是解决上述问题的LoginCommand Observable代码。最后一行是编辑。

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));