Свойство, установленное внутри асинхронного обратного вызова, не остается установленным - PullRequest
2 голосов
/ 06 января 2011

Итак, у меня странная ошибка, я надеюсь, что кто-то может мне помочь.

У меня есть следующий код для получения некоторых объектов из служб WCF RIA, это в Silverlight 4, хотя я думаю,Разве это не имеет значения.

Что мне не хватает?

public class MyModel
{
    ...

    public IEnumerable<MyEntity> Result { get; private set; }

    public void Execute()
    {
        Context.Load(Query, LoadBehavior.RefreshCurrent, o =>
        {
            if (o.HasError)
            {
                ExecuteException = o.Error;
                if (ExecuteError != null)
                    ExecuteError(this, EventArgs.Empty);
                o.MarkErrorAsHandled();
            }
            else
            {
                //I've stepped through the code and the assignment is working
                //Result != null
                Result = o.Entities; 
                if (ExecuteSuccess != null)
                    ExecuteSuccess(this, EventArgs.Empty);
                //Inside any Handler of ExecuteSuccess
                //MyModel.Result == null
                //However I set a break point after ExecuteSuccess is triggered,
                //and once again MyModel.Result != null

            }

            if (ExecuteComplete != null)
                ExecuteComplete(this, EventArgs.Empty);

            ExecuteBusy = false;

        }, false);
    }
}

Все работает, пока я не достигну этой точки:

MyModel.ExecuteSuccess += (o,e) => {
    //At this point MyModel.Result == null.  but why?
    var result = MyModel.Result;
};

1 Ответ

0 голосов
/ 06 января 2011

Да, я нашел проблему, которую я делал, чтобы сделать MVVM + RIA Services более увлекательной, в унаследованном классе я приводил MyModel.Result к MyModel.Result as IEnumerable<TEntity>;, что не работает. Я использовал MyModel.Result.OfType<TEntity> вместо этого. Я выкладываю весь код на тот случай, если он кому-нибудь пригодится.

public abstract class RiaQuery : INotifyPropertyChanged
{
    #region INotifyPropertyChanged values

    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    #endregion

    #region Query

    private EntityQuery _Query;

    public EntityQuery Query
    {
        get { return _Query; }
        private set
        {
            if (_Query != value)
            {
                _Query = value;
                RaisePropertyChanged("Query");
            }
        }
    }

    #endregion

    #region Result

    private IEnumerable _Result;

    public IEnumerable Result
    {
        get { return _Result; }
        private set
        {
            if (_Result != value)
            {
                _Result = value;
                RaisePropertyChanged("Result");
            }
        }
    }

    #endregion

    #region ExecuteBusy

    private bool _ExecuteBusy;

    public bool ExecuteBusy
    {
        get { return _ExecuteBusy; }
        private set
        {
            if (_ExecuteBusy != value)
            {
                _ExecuteBusy = value;
                RaisePropertyChanged("ExecuteBusy");
            }
        }
    }

    #endregion

    #region ExecuteCommand

    private DelegateCommand _ExecuteCommand;

    public DelegateCommand ExecuteCommand
    {
        get
        {
            if (_ExecuteCommand == null)
            {
                _ExecuteCommand = new DelegateCommand(o => Execute(o), o => !ExecuteBusy);
            }
            return _ExecuteCommand;
        }
    }

    #endregion

    #region ExecuteException

    private Exception _ExecuteException;

    public Exception ExecuteException
    {
        get { return _ExecuteException; }
        private set
        {
            if (_ExecuteException != value)
            {
                _ExecuteException = value;
                RaisePropertyChanged("ExecuteException");
            }
        }
    }

    #endregion

    public event EventHandler ExecuteBegin;
    public event EventHandler ExecuteComplete;
    public event EventHandler ExecuteSuccess;
    public event EventHandler ExecuteError;

    protected  DomainContext Context;

    public bool CreateQueryEachTime { get; set; }

    public RiaQuery(DomainContext context)
    {
        if (context == null) throw new ArgumentException("context");
        Context = context;
    }

    public void Execute(object param)
    {
        ExecuteBusy = true;

        if (ExecuteBegin != null)
            ExecuteBegin(this, EventArgs.Empty);

        if (CreateQueryEachTime || Query == null)
            CreateQueryInternal();

        Context.Load(Query, LoadBehavior.RefreshCurrent, o =>
        {
            if (o.HasError)
            {
                ExecuteException = o.Error;
                if (ExecuteError != null)
                    ExecuteError(this, EventArgs.Empty);
                o.MarkErrorAsHandled();
            }
            else
            {
                Result = o.Entities;
                if (ExecuteSuccess != null)
                    ExecuteSuccess(this, EventArgs.Empty);
            }

            if (ExecuteComplete != null)
                ExecuteComplete(this, EventArgs.Empty);

            ExecuteBusy = false;

        }, false);
    }

    private void CreateQueryInternal()
    {
        Query = CreateQuery();
    }

    protected abstract EntityQuery CreateQuery();
}

public abstract class RiaQuery<TContext> : RiaQuery
    where TContext : DomainContext
{
    new protected TContext Context
    {
        get { return base.Context as TContext; }
        set { base.Context = value; }
    }

    public RiaQuery(TContext context) : base(context) { }
}

public abstract class RiaQuery<TContext,TEntity> : RiaQuery<TContext>
    where TContext : DomainContext
    where TEntity : Entity 
{
    new public EntityQuery<TEntity> Query
    {
        get { return base.Query as EntityQuery<TEntity>; }
    }

    new public IEnumerable<TEntity> Result
    {
        get { return base.Result.OfType<TEntity>(); }
    }

    public RiaQuery(TContext context) : base(context) { }
}

public class DelegateRiaQuery<TContext> : RiaQuery<TContext>
    where TContext : DomainContext
{
    protected Func<TContext, EntityQuery> CreateQueryDelegate;

    public DelegateRiaQuery(TContext context, Func<TContext, EntityQuery> createQueryDelegate)
        : base(context)
    {
        if (createQueryDelegate == null) throw new ArgumentException("createQueryDelegate");
        CreateQueryDelegate = createQueryDelegate;
    }

    protected override EntityQuery CreateQuery()
    {
        return CreateQueryDelegate(Context);
    }
}

public class DelegateRiaQuery<TContext, TEntity> : RiaQuery<TContext, TEntity> 
    where TContext : DomainContext 
    where TEntity : Entity
{
    protected Func<TContext, EntityQuery<TEntity>> CreateQueryDelegate;

    public DelegateRiaQuery(TContext context, Func<TContext, EntityQuery<TEntity>> createQueryDelegate) : base(context)
    {
        if (createQueryDelegate == null) throw new ArgumentException("createQueryDelegate");
        CreateQueryDelegate = createQueryDelegate;
    }

    protected override EntityQuery CreateQuery()
    {
        return CreateQueryDelegate(Context);
    }
}

Использование выглядит следующим образом:

public class MyModel : INotifyPropertyChanged
{
    ...

    public DelegateRiaQuery<MyContxt,MyEntity> MyModelOperation { get; private set; }

    public MyModel()
    {
        var context = new MyContext();
        MyModelOperation = new DelegateRiaQuery(context, c => c.GetMyModelEntitiesQuery(this.Property1));
    }
}
...