如何在依赖属性上提升属性更改事件?

Mua*_*Dib 62 wpf binding

好的,所以我有两个属性的控件.其中一个是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?
    }    
}
Run Code Online (Sandbox Code Playgroud)

如果我使用的是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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我可以从一个setter在多个属性上引发PropertyChanged事件.我需要能够做同样的事情,只使用DependencyProperties.

Bre*_*yan 56

我遇到了一个类似的问题,我有一个依赖属性,我希望该类监听更改事件以从服务中获取相关数据.

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");
}
Run Code Online (Sandbox Code Playgroud)

  • 我知道我已经迟到了,但这个答案解决了我的疑惑,就像一个魅力,谢谢! (2认同)
  • 这似乎比接受的答案更合适. (2认同)

Rob*_*ney 38

  1. INotifyPropertyChanged在你的班级实施.

  2. 注册依赖项属性时,在属性元数据中指定回调.

  3. 在回调中,引发PropertyChanged事件.

添加回调:

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

提升PropertyChanged回调:

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

  • 你是如何从静态方法中获得对`PropertyChanged`事件的引用的?您首先需要转换为`INotifyPropertyChanged`并在那里访问该事件. (27认同)
  • 由于您尝试通过静态方法访问非静态成员,因此您的答案不起作用.您应该按@BrettRyan状态编辑您的答案. (6认同)
  • 这似乎不起作用。看来,如果一个对象是“DependencyObject”,WPF 引擎会忽略“INotifyPropertyChanged”并且不会订阅其事件。 (2认同)

Sam*_*Sam 10

我认为OP正在提出错误的问题.下面的代码将显示没有必要从依赖项属性手动引发PropertyChanged EVENT以实现所需的结果.执行此操作的方法是处理依赖项属性上的PropertyChanged CALLBACK,并为其他依赖项属性设置值.以下是一个工作示例.在下面的代码中,MyControl有两个依赖项属性--ActiveTabInt和ActiveTabString.当用户单击主机(MainWindow)上的按钮时,将修改ActiveTabString.依赖项属性上的PropertyChanged CALLBACK设置ActiveTabInt的值.MyControl不会手动引发PropertyChanged EVENT.

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

    }
}
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)


kar*_*fus 5

我同意 Sam 和 Xaser 的观点,并且实际上已经更进一步了。我认为你根本不应该INotifyPropertyChanged在 a 中实现接口UserControl...控件已经是 a 了DependencyObject,因此已经带有通知。添加INotifyPropertyChanged到 aDependencyObject对我来说是多余的并且“闻起来”不对。

我所做的是将两个属性实现为DependencyProperties,正如 Sam 所建议的那样,但随后只是让PropertyChangedCallback“第一个”依赖属性更改“第二个”依赖属性的值。由于两者都是依赖属性,因此两者都会自动向任何感兴趣的订阅者发出更改通知(例如数据绑定等)

在本例中,依赖属性 A 是字符串,它会触发依赖属性 B (名为 的属性)InviteText的更改。如果您希望能够通过数据绑定将一些文本完全隐藏在控件中,这将是一个常见的用例。VisibilityShowInvite

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));
Run Code Online (Sandbox Code Playgroud)

请注意,我在这里不包括UserControl签名或构造函数,因为它们没有什么特别之处;INotifyPropertyChanged他们根本不需要继承。