好的,所以我有两个属性的控件。其中一个是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");
}
}
}
我可以从一个setter在多个属性上引发PropertyChanged事件。我需要能够做同样的事情,只使用DependencyProperties。
答案 0 :(得分:49)
我遇到了一个类似的问题,我有一个依赖属性,我希望该类监听更改事件以从服务中获取相关数据。
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");
}
答案 1 :(得分:38)
在班级中实施INotifyPropertyChanged
。
注册依赖项属性时,在属性元数据中指定回调。
在回调中,引发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"));
}
}
答案 2 :(得分: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());
}
}
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>
答案 3 :(得分:3)
我同意Sam和Xaser,并且实际上已经采取了这一点。我认为你根本不应该在UserControl中实现INotifyPropertyChanged接口......控件已经是DependencyObject,因此已经附带了通知。将INotifyPropertyChanged添加到DependencyObject是多余的,并且“气味”对我来说是错误的。
我所做的是将这两个属性实现为DependencyProperties,正如Sam建议的那样,但是后来只是让“first”依赖属性中的PropertyChangedCallback改变了“second”依赖属性的值。由于两者都是依赖属性,因此两者都会自动向任何感兴趣的订阅者发送更改通知(例如数据绑定等)
在这种情况下,依赖项属性A是字符串InviteText,它触发依赖项属性B的更改,名为ShowInvite的Visibility属性。如果您希望能够通过数据绑定在控件中完全隐藏某些文本,那么这将是一个常见的用例。
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继承。
答案 4 :(得分:0)
我质疑在第二个属性上引发PropertyChanged事件的逻辑,因为它是第一个正在改变的属性。如果第二个属性值发生更改,那么可以在那里引发PropertyChanged事件。
无论如何,您的问题的答案是您应该实现INotifyPropertyChange。此接口包含PropertyChanged事件。实现INotifyPropertyChanged允许其他代码知道该类具有PropertyChanged事件,因此代码可以挂钩处理程序。实现INotifyPropertyChange后,OnPropertyChanged的if语句中的代码为:
if (PropertyChanged != null)
PropertyChanged(new PropertyChangedEventArgs("MySecondProperty"));