Как вызвать события изменения свойств в свойстве зависимостей?



ОК, так что у меня есть этот элемент управления с двумя свойствами. Один из них-свойство DependencyProperty, другой - "псевдоним" для первого. То, что мне нужно сделать, это поднять событие PropertyChanged для второго (псевдоним) при изменении первого.



Примечание: Я использую DependencyObjects, а не INotifyPropertyChanged (пробовал, не работает, потому что мой элемент управления является подклассом 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");
}
}
}


где я могу поднять PropertyChanged события на нескольких свойствах от одного сеттера. Мне нужно быть в состоянии сделать то же самое, только используя DependencyProperties.

605   5  

5 ответов:

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

Я думаю, что ОП-это неправильный вопрос. Приведенный ниже код покажет, что для достижения желаемого результата не требуется вручную вызывать событие PropertyChanged из свойства зависимостей. Способ сделать это-обработать обратный вызов PropertyChanged для свойства зависимостей и установить значения для других свойств зависимостей там. Ниже приведен рабочий пример. В приведенном ниже коде MyControl имеет два свойства зависимостей-ActiveTabInt и ActiveTabString. Когда пользователь нажимает кнопка на хосте (MainWindow), ActiveTabString изменяется. Обратный вызов PropertyChanged для свойства зависимостей задает значение ActiveTabInt. Событие PropertyChanged не вызывается 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>

приложение.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>

Я согласен с Сэмом и Xaser и на самом деле взял это немного дальше. Я не думаю, что вы должны реализовывать интерфейс INotifyPropertyChanged в UserControl вообще...элемент управления уже является DependencyObject и поэтому уже поставляется с уведомлениями. Добавление INotifyPropertyChanged к DependencyObject является избыточным и" пахнет " неправильно для меня.

то, что я сделал, это реализовать оба свойства как DependencyProperties, как предлагает Сэм, но тогда просто имел PropertyChangedCallback из "первого" свойства зависимостей изменяет значение" второго " свойства зависимостей. Поскольку оба являются свойствами зависимостей, оба будут автоматически вызывать уведомления об изменениях для всех заинтересованных подписчиков (например, привязка данных и т. д.)

в этом случае свойство зависимостей A-это строка InviteText, которая вызывает изменение свойства зависимостей B, свойства видимости с именем ShowInvite. Это был бы общий случай использования, если у вас есть какой-то текст, который вы хотите чтобы иметь возможность полностью скрываться в элементе управления с помощью привязки данных.

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

обратите внимание, что я не включаю подпись UserControl или конструктор здесь, потому что в них нет ничего особенного; им вообще не нужно подкласс из INotifyPropertyChanged.

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

во всяком случае, ответ на ваш вопрос заключается в том, что вы должны реализовать INotifyPropertyChange. Этот интерфейс содержит событие PropertyChanged. Реализация INotifyPropertyChanged позволяет другому коду знать, что класс имеет событие PropertyChanged, так что код может подключить обработчик. После реализации INotifyPropertyChange код, который входит в Оператор if вашего OnPropertyChanged:

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

Comments

    Ничего не найдено.