1

개체를 가져 와서 속성을 가져 오는 메서드가있는 기본 DependencyObject 클래스가 있고 INotifyPropertyChanged를 구현하는 형식 인 각 속성에 대해 새 PropertyChangedEventHandler를 추가합니다. 이제 처리기 메서드에서 "보낸 사람"개체 및 PropertyChangedEventArgs "e"매개 변수를 가져옵니다. 내 질문은, 사람이 동적으로 INotifyPropertyChanged 구현하는 형식의 속성을 보낸 경우 속성 이름을 동적으로 얻는 방법을 알고 있습니다.

여기 내가 함께 일하고있다 :

public class BaseDependencyObject : DependencyObject, INotifyPropertyChanged
{
    public BaseDependencyObject()
    {

    }

    protected void SetValues(Object thisObject, Object entity)
    {
        try
        {
            PropertyInfo[] properties = entity.GetType().GetProperties();
            foreach (PropertyInfo property in properties)
            {
                var value = property.GetValue(entity, null);
                var valueIsEntity = value is System.ServiceModel.DomainServices.Client.Entity;
                var thisObjectsProperty = thisObject.GetType().GetProperty(property.Name);

                if (thisObjectsProperty != null && value != null)
                {
                    if (valueIsEntity)
                    {
                        if (thisObjectsProperty.PropertyType.GetInterface("INotifyPropertyChanged", true) != null)
                        {
                            var propertyInstance = Activator.CreateInstance(thisObjectsProperty.PropertyType);

                            ((INotifyPropertyChanged)propertyInstance).PropertyChanged += new PropertyChangedEventHandler(Object_PropertyChanged);
                        }

                        SetValues(thisObjectsProperty, value);
                    }

                    else if (thisObjectsProperty.PropertyType.GetInterface("ICollection", true) != null
                        && thisObjectsProperty.PropertyType.GetGenericArguments().Count() > 0)
                    {
                        Type genericType = thisObjectsProperty.PropertyType.GetGenericArguments()[0];

                        var observableCollection = Activator.CreateInstance(thisObjectsProperty.PropertyType) as IList;

                        if (observableCollection is INotifyCollectionChanged)
                            ((INotifyCollectionChanged)observableCollection).CollectionChanged += this.Object_CollectionChanged;

                        if (observableCollection is INotifyPropertyChanged)
                            ((INotifyPropertyChanged)observableCollection).PropertyChanged += new PropertyChangedEventHandler(Object_PropertyChanged);

                        foreach (var item in (IEnumerable)value)
                        {
                            var newItem = Activator.CreateInstance(genericType);

                            if (newItem != null)
                            {
                                SetValues(newItem, item);
                                observableCollection.Add(newItem);
                            }
                        }
                    }

                    else
                    {
                        thisObjectsProperty.SetValue(thisObject, value, null);

                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    protected void Object_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                foreach (var item in e.NewItems)
                {
                    if (item is INotifyPropertyChanged)
                    {
                        ((INotifyPropertyChanged)item).PropertyChanged += new PropertyChangedEventHandler(Object_PropertyChanged);
                    }
                }
                break;

            case NotifyCollectionChangedAction.Remove:
                foreach (var item in e.OldItems)
                {
                    if (item is INotifyPropertyChanged)
                    {
                        ((INotifyPropertyChanged)item).PropertyChanged -= this.Object_PropertyChanged;
                    }
                }
                break;
        }

    }

    protected void Object_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        this.NotifyPropertyChanged(e.PropertyName);
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;

        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));

    }
}

SetValues 메서드의 첫 번째 매개 변수는 뷰 모델에서 사용할 DependencyObject 형식입니다. 두 번째 매개 변수는 DomainService의 Context.LoadOperation에서 반환되는 엔터티입니다.

내 문제는 INotifyCollectionChanged.CollectionChanged가 발생했을 때 발생합니다. 컬렉션의 속성 이름으로 PropertyChanged 이벤트를 발생시킬 수 있어야합니다. 그래서 누군가가 조언을한다면 크게 감사하겠습니다. 미리 감사드립니다.

편집하다

이벤트를 발생시키는 속성 이름을 가져 오는 방법을 알아 냈습니다. 다음은 PropertyChangedEventHandler의 편집 된 버전입니다.

protected void Object_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        var properties = this.GetType().GetProperties().Where(x => x.PropertyType == sender.GetType()).ToArray();

        foreach (var property in properties)
        {
            this.NotifyPropertyChanged(property.Name);
        }

        //this.NotifyPropertyChanged(e.PropertyName);
    }

기본적으로 이것은 내가 찾고있는 것을 수행하지만, 나는 아직도 무언가를 제대로하지 않습니다. 다른 유형의 속성 인 ObservableCollection이 추가 될 때 UIElement는 여전히 업데이트되지 않습니다.

다음은 내 DependencyObjects 및 ViewModel의 예입니다.

public class LOB : DependencyObject
{
    public Int32 ID
    {
        get { return (Int32)GetValue(IDProperty); }
        set
        {
            SetValue(IDProperty, value);
            NotifyPropertyChanged("ID");
        }
    }

    public static readonly DependencyProperty IDProperty =
    DependencyProperty.Register("ID", typeof(Int32), typeof(LOB), null);

    public ObservableCollection<Group> Groups
    {
        get { return (ObservableCollection<Group>)GetValue(GroupsProperty); }
        set
        {
            SetValue(GroupsProperty, value);
            NotifyPropertyChanged("Groups");
        }
    }

    public static readonly DependencyProperty GroupsProperty =
    DependencyProperty.Register("Groups", typeof(ObservableCollection<Group>), typeof(LOB), new PropertyMetadata(null, OnGroupsPropertyChanged));

    static void OnGroupsPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        if (e.NewValue != null)
        {
            ((INotifyCollectionChanged)e.NewValue).CollectionChanged += new NotifyCollectionChangedEventHandler(((LOB)obj).Object_CollectionChanged);
            ((INotifyPropertyChanged)e.NewValue).PropertyChanged += new PropertyChangedEventHandler(((LOB)obj).Object_PropertyChanged);
        }
        if (e.OldValue != null)
        {
            ((INotifyCollectionChanged)e.OldValue).CollectionChanged -= ((LOB)obj).Object_CollectionChanged;
            ((INotifyPropertyChanged)e.OldValue).PropertyChanged -= ((LOB)obj).Object_PropertyChanged;
        }
    }

}

public class Group : DependencyObject
{
    public Int32 ID
    {
        get { return (Int32)GetValue(IDProperty); }
        set
        {
            SetValue(IDProperty, value);
            NotifyPropertyChanged("ID");
        }
    }

    public static readonly DependencyProperty IDProperty =
    DependencyProperty.Register("ID", typeof(Int32), typeof(Group), null);

    public String GroupName
    {
        get { return (String)GetValue(GroupNameProperty); }
        set
        {
            SetValue(GroupNameProperty, value);
            NotifyPropertyChanged("GroupName");
        }
    }

    public static readonly DependencyProperty GroupNameProperty =
    DependencyProperty.Register("GroupName", typeof(String), typeof(Group), null);

}

public class MyViewModel : DependencyObject
{
    public static readonly DependencyProperty LobCollectionProperty =
        DependencyProperty.Register("LobCollection",
            typeof(ObservableCollection<LOB>),
            typeof(MyViewModel),
            new PropertyMetadata(null, LobCollectionPropertyChanged));

    public ObservableCollection<LOB> LobCollection
    {
        get { return (ObservableCollection<MainBusinessLine>)GetValue(LobCollectionPropertyChanged); }
        set
        {
            SetValue(MainBusinessLineCollectionProperty, value);
            NotifyPropertyChanged("LobCollection");
        }
    }

    static void LobCollectionPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        var viewModel = obj as MyViewModel;

        if (viewModel == null)
            return;

        if (e.OldValue != null)
        {
            ((INotifyCollectionChanged)e.OldValue).CollectionChanged -= viewModel.LobCollection_Changed;
        }

        if (e.NewValue != null)
        {
            ((INotifyCollectionChanged)e.NewValue).CollectionChanged += viewModel.LobCollection_Changed;
        }

    }

    void LobCollection_Changed(object sender, NotifyCollectionChangedEventArgs e)
    {
        NotifyPropertyChanged("LobCollection");
    }
}  


  • 귀하의 질문을 올바르게 이해하도록하겠습니다. " public class Foo : INotifyPropertyChanged {INotifyCollectionChanged collection; } "로 설정하고 CollectionChanged 이벤트가 발생하면 PropertyChanged 이벤트가 소유 클래스에서 실행되기를 원합니다. 그 맞습니까? - David Yaw
  • 그래 너가 옳아. 게다가 원래의 게시물을 편집하여 업데이트 된 버전을 보여주었습니다. 그게 가장 큰 해결책은 아니지만 지금은 다른 관찰 가능한 컬렉션에있는 관찰 가능한 컬렉션에 추가 할 수 있기를 원합니다. - jhorton
  • LOB 및 그룹 수업에서하는 일이 나에게 가장 적합합니다. 기본 클래스에서 처리하는 것은 가능하지만 DependancyProperty와 INotifyPropertyChanged를 혼합하면 더 어려워집니다. 기술적으로 INotifyPropertyChanged 계약을 따르지 않은 것으로 보입니다. 속성 값을 변경하지 않았기 때문에 내부의 컬렉션에 있음을 알 수 있습니다. 이 작업을 수행하는 표준 방법은 CollectionChanged 이벤트를 발생시키고 그대로 두는 것입니다. - David Yaw
  • 먼저 xaml에 약간의 변경을 가했을 때 UIElement가 새 항목을 올바르게 표시하고 추가했는지 이제 추가해야한다고 생각합니다. 그래서 그것은 DependencyProperty와 INotifyPropertyChanged를 사용하여 지금 설계 해 놓았습니까? "라는 질문을 던졌습니다. 그리고 위의 진술에 의해 나는 추측했다. 그래서, 더 나은 관행, DP의 또는 INotify의 생각은 무엇입니까? 그리고 CollectionChanged 이벤트를 남기라고했습니다. 해당 컬렉션 속성에 대해 PropertyChanged 이벤트를 발생시키지 않아도됩니까? 그리고 다윗에게 응답 해 주셔서 감사드립니다. 내 머리가 벽에 부딪혀 아프다. - jhorton
  • DependancyObject & amp;에 대한 나의 일반적인 철학 INotifyPropertyChanged는 둘 중 하나를 사용하는 것입니다. 동일한 클래스에서 둘 다 사용해야하는 경우 DependancyProperty에 대한 PropertyChanged 이벤트가 발생하지 않습니다. 해당 속성에 바인딩하는 것이 이미 DP에서 변경 알림을 받으면 PropertyChanged는 필요하지 않습니다. - David Yaw

1 답변


2

위의 대화 후, 이것은 다소 의의가 있지만 하위 클래스가 정의한 속성에서 컬렉션이 변경 될 때 PropertyChanged 이벤트를 발생시키는 기본 클래스를 구현하는 방법에 대해 생각했습니다. 내가 말했듯이, 약간 비표준이지만, 어떻게 할 수 있나.

class FancyCollectionAndPropertyChangedBase : INotifyPropertyChanged
{
    private Dictionary<ICollectionChanged, String> collectionNameLookup = new Dictionary<ICollectionChanged, String>();

    protected FancyCollectionAndPropertyChangedBase()
    {
        this.PropertyChanged += MyPropertyChanged;
    }

    private void MyPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if(this.collectionNameLookup.ContainsValue(e.PropertyName)
        {
            KeyValuePair<INotifyCollectionChanged, String> oldValue = this.collectionNameLookup.First(kvp => kvp.Value == e.Name);
            oldValue.Key -= MyCollectionChanged;
            this.collecitonNameLookup.Remove(oldValue.Key);

            INotifyCollectionChanged collection = this.GetType().GetProperty(e.PropertyName, BindingFlags.FlattenHierarchy).GetValue(this, null);
            collection.CollectionChanged += MyCollectionChanged;
            this.collectionNameLookup.Add(collection, e.Name);
        }
        else if(typeof(INotifyCollectionChanged).IsAssignableFrom(this.GetType().GetProperty(e.PropertyName,  BindingFlags.FlattenHierarchy).PropertyType))
        {
            // Note: I may have gotten the IsAssignableFrom statement, above, backwards. 
            INotifyCollectionChanged collection = this.GetType().GetProperty(e.PropertyName, BindingFlags.FlattenHierarchy).GetValue(this, null);
            collection.CollectionChanged += MyCollectionChanged;
            this.collectionNameLookup.Add(collection, e.Name);
        }
    }

    private void MyCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        this.NotifyPropertyChanged(this.collectionNameLookup[sender];
    }
}


  • David, 당신이 위에서 게시 한 코드의 기초를 사용하여 Base 클래스에 구현 한 사실을 알려 드리고자합니다. 모든 것이 원활하게 진행되고 있습니다. 이 일을 도와 주실 시간을 내 주셔서 감사합니다. 모든 것을 혼합하여 속임수로 사용했기 때문에 이것을 답으로 표시하겠습니다. 또한 DependencyObject에서 상속을 제거하고 INotify 인터페이스 만 구현했습니다. 앞으로 누군가가 완성 된 코드를 볼 필요가 있다면 게시하게되어 기쁩니다. 다시 한번 감사드립니다. - jhorton

관련된 질문

최근 질문