Development Tip

종속성 속성에서 속성 변경 이벤트를 발생시키는 방법은 무엇입니까?

yourdevel 2020. 12. 4. 21:03
반응형

종속성 속성에서 속성 변경 이벤트를 발생시키는 방법은 무엇입니까?


좋아, 두 가지 속성이있는이 컨트롤이 있습니다. 이들 중 하나는 DependencyProperty이고 다른 하나는 첫 번째 항목에 대한 "별칭"입니다. 내가해야 할 일은 첫 번째 이벤트가 변경 될 때 두 번째 이벤트 (별칭)에 대한 PropertyChanged 이벤트를 발생시키는 것입니다.

참고 : INotifyPropertyChanged가 아닌 DependencyObjects를 사용하고 있습니다 (내 컨트롤이 하위 클래스 ListView이기 때문에 작동하지 않았습니다)

이 같은.....

protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
    base.OnPropertyChanged(e);
    if (e.Property == MyFirstProperty)
    {
        RaiseAnEvent( MySecondProperty ); /// what is the code that would go here?
    }    
}

INotify를 사용하고 있다면 이렇게 할 수 있습니다 ...

public string SecondProperty
{
    get
    {
        return this.m_IconPath;
    }
}

public string IconPath
{
    get
    {
        return this.m_IconPath;
    }
    set
    {
        if (this.m_IconPath != value)
        {
            this.m_IconPath = value;
        this.SendPropertyChanged("IconPath");
        this.SendPropertyChanged("SecondProperty");
        }
    }
}

하나의 setter에서 여러 속성에 대한 PropertyChanged 이벤트를 발생시킬 수 있습니다. DependencyProperties 만 사용하여 동일한 작업을 수행 할 수 있어야합니다.


  1. INotifyPropertyChanged수업에서 구현 하십시오.

  2. 종속성 속성을 등록 할 때 속성 메타 데이터에 콜백을 지정합니다.

  3. 콜백에서 PropertyChanged 이벤트를 발생시킵니다.

콜백 추가 :

public static DependencyProperty FirstProperty = DependencyProperty.Register(
  "First", 
  typeof(string), 
  typeof(MyType),
  new FrameworkPropertyMetadata(
     false, 
     new PropertyChangedCallback(OnFirstPropertyChanged)));

올리기 PropertyChanged콜백에서 :

private static void OnFirstPropertyChanged(
   DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
   PropertyChangedEventHandler h = PropertyChanged;
   if (h != null)
   {
      h(sender, new PropertyChangedEventArgs("Second"));
   }
}

클래스가 서비스에서 관련 데이터를 가져 오기 위해 변경 이벤트를 수신하기를 원하는 종속성 속성이있는 비슷한 문제가 발생했습니다.

public static readonly DependencyProperty CustomerProperty = 
    DependencyProperty.Register("Customer", typeof(Customer),
        typeof(CustomerDetailView),
        new PropertyMetadata(OnCustomerChangedCallBack));

public Customer Customer {
    get { return (Customer)GetValue(CustomerProperty); }
    set { SetValue(CustomerProperty, value); }
}

private static void OnCustomerChangedCallBack(
        DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
    CustomerDetailView c = sender as CustomerDetailView;
    if (c != null) {
        c.OnCustomerChanged();
    }
}

protected virtual void OnCustomerChanged() {
    // Grab related data.
    // Raises INotifyPropertyChanged.PropertyChanged
    OnPropertyChanged("Customer");
}

OP가 잘못된 질문을하고 있다고 생각합니다. 아래 코드는 원하는 결과를 얻기 위해 종속성 속성에서 PropertyChanged EVENT를 수동으로 발생시킬 필요가 없음을 보여줍니다. 이를 수행하는 방법은 종속성 속성에서 PropertyChanged CALLBACK을 처리하고 다른 종속성 속성에 대한 값을 설정하는 것입니다. 다음은 작동하는 예입니다. 아래 코드에서 MyControl에는 ActiveTabInt 및 ActiveTabString의 두 가지 종속성 속성이 있습니다. 사용자가 호스트 (MainWindow)의 버튼을 클릭하면 ActiveTabString이 수정됩니다. 종속성 속성의 PropertyChanged CALLBACK은 ActiveTabInt의 값을 설정합니다. PropertyChanged EVENT는 MyControl에 의해 수동으로 발생하지 않습니다.

MainWindow.xaml.cs

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
        ActiveTabString = "zero";
    }

    private string _ActiveTabString;
    public string ActiveTabString
    {
        get { return _ActiveTabString; }
        set
        {
            if (_ActiveTabString != value)
            {
                _ActiveTabString = value;
                RaisePropertyChanged("ActiveTabString");
            }
        }
    }

    private int _ActiveTabInt;
    public int ActiveTabInt
    {
        get { return _ActiveTabInt; }
        set
        {
            if (_ActiveTabInt != value)
            {
                _ActiveTabInt = value;
                RaisePropertyChanged("ActiveTabInt");
            }
        }
    }

    #region INotifyPropertyChanged implementation
    public event PropertyChangedEventHandler PropertyChanged;

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

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        ActiveTabString = (ActiveTabString == "zero") ? "one" : "zero";
    }

}

public class MyControl : Control
{
    public static List<string> Indexmap = new List<string>(new string[] { "zero", "one" });


    public string ActiveTabString
    {
        get { return (string)GetValue(ActiveTabStringProperty); }
        set { SetValue(ActiveTabStringProperty, value); }
    }

    public static readonly DependencyProperty ActiveTabStringProperty = DependencyProperty.Register(
        "ActiveTabString",
        typeof(string),
        typeof(MyControl), new FrameworkPropertyMetadata(
            null,
            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
            ActiveTabStringChanged));


    public int ActiveTabInt
    {
        get { return (int)GetValue(ActiveTabIntProperty); }
        set { SetValue(ActiveTabIntProperty, value); }
    }
    public static readonly DependencyProperty ActiveTabIntProperty = DependencyProperty.Register(
        "ActiveTabInt",
        typeof(Int32),
        typeof(MyControl), new FrameworkPropertyMetadata(
            new Int32(),
            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));


    static MyControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl), new FrameworkPropertyMetadata(typeof(MyControl)));

    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
    }


    private static void ActiveTabStringChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        MyControl thiscontrol = sender as MyControl;

        if (Indexmap[thiscontrol.ActiveTabInt] != thiscontrol.ActiveTabString)
            thiscontrol.ActiveTabInt = Indexmap.IndexOf(e.NewValue.ToString());

    }
}

MainWindow.xaml

    <StackPanel Orientation="Vertical">
    <Button Content="Change Tab Index" Click="Button_Click" Width="110" Height="30"></Button>
    <local:MyControl x:Name="myControl" ActiveTabInt="{Binding ActiveTabInt, Mode=TwoWay}" ActiveTabString="{Binding ActiveTabString}"></local:MyControl>
</StackPanel>

App.xaml

<Style TargetType="local:MyControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:MyControl">
                    <TabControl SelectedIndex="{Binding ActiveTabInt, Mode=TwoWay}">
                        <TabItem Header="Tab Zero">
                            <TextBlock Text="{Binding ActiveTabInt}"></TextBlock>
                        </TabItem>
                        <TabItem Header="Tab One">
                            <TextBlock Text="{Binding ActiveTabInt}"></TextBlock>
                        </TabItem>
                    </TabControl>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

I agree with Sam and Xaser and have actually taken this a bit farther. I don't think you should be implementing the INotifyPropertyChanged interface in a UserControl at all...the control is already a DependencyObject and therefore already comes with notifications. Adding INotifyPropertyChanged to a DependencyObject is redundant and "smells" wrong to me.

What I did is implement both properties as DependencyProperties, as Sam suggests, but then simply had the PropertyChangedCallback from the "first" dependency property alter the value of the "second" dependency property. Since both are dependency properties, both will automatically raise change notifications to any interested subscribers (e.g. data binding etc.)

In this case, dependency property A is the string InviteText, which triggers a change in dependency property B, the Visibility property named ShowInvite. This would be a common use case if you have some text that you want to be able to hide completely in a control via data binding.

    public string InviteText  
    {
        get { return (string)GetValue(InviteTextProperty); }
        set { SetValue(InviteTextProperty, value); }
    }

    public static readonly DependencyProperty InviteTextProperty =
        DependencyProperty.Register("InviteText", typeof(string), typeof(InvitePrompt), new UIPropertyMetadata(String.Empty, OnInviteTextChanged));

    private static void OnInviteTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        InvitePrompt prompt = d as InvitePrompt;
        if (prompt != null)
        {
            string text = e.NewValue as String;
            prompt.ShowInvite = String.IsNullOrWhiteSpace(text) ? Visibility.Collapsed : Visibility.Visible;
        }
    }

    public Visibility ShowInvite
    {
        get { return (Visibility)GetValue(ShowInviteProperty); }
        set { SetValue(ShowInviteProperty, value); }
    }

    public static readonly DependencyProperty ShowInviteProperty =
        DependencyProperty.Register("ShowInvite", typeof(Visibility), typeof(InvitePrompt), new PropertyMetadata(Visibility.Collapsed));

Note I'm not including the UserControl signature or constructor here because there is nothing special about them; they don't need to subclass from INotifyPropertyChanged at all.


I question the logic of raising a PropertyChanged event on the second property when it's the first property that's changing. If the second properties value changes then the PropertyChanged event could be raised there.

At any rate, the answer to your question is you should implement INotifyPropertyChange. This interface contains the PropertyChanged event. Implementing INotifyPropertyChanged lets other code know that the class has the PropertyChanged event, so that code can hook up a handler. After implementing INotifyPropertyChange, the code that goes in the if statement of your OnPropertyChanged is:

if (PropertyChanged != null)
    PropertyChanged(new PropertyChangedEventArgs("MySecondProperty"));

참고URL : https://stackoverflow.com/questions/2480366/how-to-raise-property-changed-events-on-a-dependency-property

반응형