2010-02-01 4 views
4

Мне нравится идея расширения на клиентских классах, которые являются контрактами данных служб WCF с использованием частичных классов. Но я столкнулся с проблемой, которая значительно портит сторону.Подписка на PropertyChanged of DataContract proxy classe службы WCF

Представьте на стороне сервера, у меня есть класс:

[DataContract] 
public class SolidObject 
{ 
    [DataMember] 
    public Point Position { get; set; } 
    [DataMember] 
    public Size Size { get; set; } 
} 

На стороне клиента у меня есть прокси-класс сгенерированного, который используется там в слой бизнес-логики. В соответствии с потребностями бизнес-логики я продлить это так:

public partial class SolidObject 
{ 
    public Rect Bounds { get { return new Rect(Position.X - Size.Width/2, Position.Y - Size.Height/2, Size.Width, Size.Height); }} 
} 

Теперь я хочу, чтобы убедиться, что в любое время либо установки или изменения размера, то Bounds Chage событие вызывается. Это легко сделать по коду:

PropertyChanged += (sender, e) => 
    { 
     if ((e.PropertyName == "Position") || (e.PropertyName == "Size")) PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Bounds")); 
    }; 

Вопрос в том, где хорошее место для размещения этого кода.

Если объекты не были созданы вызовом службы, я бы поместил его в конструктор. Но службы WCF игнорируют конструкторы на стороне клиента, см. constructor not showing up in my WCF client, serialization problem?.

Теперь, после ответа службы, моя программа выполняет поиск по иерархии контрактов данных, получает желаемые объекты и добавляет обработчики событий. Но я не думаю, что это правильно.

Так что мне интересно, где это лучше делать или, может быть, рассуждать о том, что весь подход должен быть изменен. Любые идеи оценили.

ответ

4

Вы можете использовать [OnDeserlialized] атрибут, чтобы вставить метод, который вызывается после deserizlization.

public partial class SolidObject 
{ 
    public Rect Bounds 
    { 
     get 
     { 
      return new Rect(Position.X - Size.Width/2, Position.Y - Size.Height/2, Size.Width, Size.Height); 
     } 
    } 

    [OnDeserialized] 
    public void Initialize(StreamingContext streamingContext) 
    { 
     PropertyChanged += (sender, e) => 
     { 
      if ((e.PropertyName == "Position") || (e.PropertyName == "Size")) 
       PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Bounds")); 
     }; 
    } 
} 
+0

Отлично! Это то, что я искал. Единственное замечание заключается в том, что он исключил исключение, пока я не сделал этот метод общедоступным. –

+0

ОК, я отредактировал ответ, чтобы включить это исправление. –

+0

Это замечательно! Имел аналогичную проблему, и это ее решило. Благодаря! – ScottCher

2

Я бы рекомендовал использовать модель представления, а не частичный класс.

public class SolidObjectViewModel : INotifyPropertyChanged 
{ 
    private SolidObject _solidObject; 

    public SolidObjectViewModel(SolidObject solidObject) 
    { 
     _solidObject = solidObject; 
     _solidObject.PropertyChanged += (sender, e) => 
     { 
      bool positionChanged = e.PropertyName == "Position"; 
      bool sizeChanged = e.PropertyName == "Size"; 
      if (positionChanged) 
       FirePropertyChanged("Position"); 
      if (sizeChanged) 
       FirePropertyChanged("Size"); 
      if (positionChanged || sizeChanged) 
       FirePropertyChanged("Bounds"); 
     }; 
    } 

    public Point Position 
    { 
     get { return _solidObject.Position; } 
     set { _solidObject.Position = value; } 
    } 

    public Size Size 
    { 
     get { return _solidObject.Size; } 
     set { _solidObject.Size = value; } 
    } 

    public Rect Bounds 
    { 
     get 
     { 
      return new Rect(Position.X - Size.Width/2, Position.Y - Size.Height/2, Size.Width, Size.Height); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    private void FirePropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 
+0

+1, но ответ будет лучше, если вы сказали _why_ вы предлагаете модель обзора. –

+0

Майкл, спасибо, что вызвал это, я до сих пор не знаю ответа. Что касается вашего подхода, это может сработать, но не всегда. Я использую ViewModel, но для других целей. Я думаю, что модели просмотра предназначены для управления пользовательским интерфейсом. Однако в этом случае мне нужны дополнительные свойства на бизнес-уровне для реализации физической модели, которая не зависит от уровня представления. Итак, я поддержал, но не выбрал его как решение. –

+0

Возможно, модель просмотра является неправильным термином для шаблона в этом контексте. Причина, по которой этот метод будет работать, и частичный класс не будет заключаться в том, что это дает вам крючок инициализации. –

0

Я бы сказал, не использовать сгенерированный класс, если есть бизнес-логика, чтобы быть implemented.Keep ваша модель чистой, имея на стороне клиента реализации SolidObject. Когда вы создаете прокси-серверы, вы можете использовать опцию для классов повторного использования из этой DLL.

Это оленья кожа имеет смысл для объекта, чтобы присоединить к своей собственной реализации event.The будет ..

[DataContract] 
public class SolidObject 
{ 
    [DataMember] 
    public Point Position 
    { 
     get { return _position; } 
     set 
      { 
      position = value; 
      FirePropertyChanged("Position"); 
      FirePropertyChanged("Bounds"); 
      } 
    } 

    public Size Size 
    { 
    //similar to position 
    } 

    public Rect Bounds { get { return new Rect(Position.X - Size.Width/2, Position.Y - Size.Height/2, Size.Width, Size.Height); }} 
} 
+0

Не могли бы вы прояснить, должен ли код, который вы предлагаете, проживать на стороне клиента или на стороне сервера? –

+0

Этот код должен находиться на стороне клиента. Затем вы можете использовать опцию повторного использования типов при создании прокси. –

+0

Тогда мне интересно, что будет на стороне сервера. Будут ли эти классы иметь одинаковые имена и пространства имен и сливаться с ними? –

 Смежные вопросы

  • Нет связанных вопросов^_^