我的问题涉及Silverlight(但我猜WPF也是如此)。
基本上我知道,如何在用户控件中创建依赖项属性以及如何使其工作。但是我试图做的并没有成功的是:在类中创建依赖属性(或多个),这个类将成为我的用户控件的依赖属性。
换句话说:
// my UserControl
public class DPTest : UserControl
{
// dependency property, which type is a class, and this class will be holding other dependency properties
public static readonly DependencyProperty GroupProperty =
DependencyProperty.Register("Group", typeof(DPGroup), typeof(DPTest), new PropertyMetadata(new DPGroup(), OnPropertyChanged));
public DPGroup Group
{
get { return (DPGroup)GetValue(GroupProperty); }
set { SetValue(GroupProperty, value); }
}
// this occurs only when property Group will change, but not when a member of property Group will change
static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DPTest g = d as DPTest;
// etc.
}
}
// a class, where I want to hold my dependency properties
public class DPGroup : DependencyObject
{
public static readonly DependencyProperty MyProperty1Property =
DependencyProperty.RegisterAttached("MyProperty1", typeof(int), typeof(DPGroup), new PropertyMetadata(1, OnPropertyChanged));
public int MyProperty1
{
get { return (int)GetValue(MyProperty1Property); }
set { SetValue(MyProperty1Property, value); }
}
// I would like to notify "the parent" (which means user control "DPTest" ), that member MyProperty1 has changed
static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DPTest g = d as DPTest;
if (g != null) g.textBox1.Text = g.Group.MyProperty1.ToString();
}
}
我想要实现的是通知(在XAML的设计时)用户控件DPTest
,Group
属性的成员(Group.MyProperty1
)改变了它的值< / b>。我设法在运行时实现它,例如使用DPGroup
类中定义的事件处理程序,但这在xaml中的设计时不起作用。
<Grid x:Name="LayoutRoot" Background="White">
<local:DPTest>
<local:DPTest.Group>
<local:DPGroup MyProperty1="2"/>
</local:DPTest.Group>
</local:DPTest>
</Grid>
它有效,但只是第一次,在创建标签期间:
<local:DPGroup MyProperty1="2"/>
之后,更改MyProperty1
的值,不会触发DPTest.OnPropertyChange
。可能会触发DBGroup.OnPropertyChanged
,但这当然不会通知用户控件DPTest
。 那么如何让DPTest
知道Group.MyProperty1
已经改变了?
我不希望从MyProperty1
到用户控件DPTest
内创建的相应属性进行任何绑定(不重复属性),重点是在一个单独的类中有一组属性,所以我可以不止一次使用这个组,比如:
// my UserControl
public class DPTest : UserControl
{
public DPGroup Group1 { ... }
public DPGroup Group2 { ... }
}
我看到UIElement.RenderTransform
的一些类比(假设它是我的Group
属性),例如ScaleTransform
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RenderTransform>
<ScaleTransform ScaleX="0.4"/>
</Grid.RenderTransform>
</Grid>
ScaleX
与MyProperty1
类似。 不同之处在于,ScaleX
(在XAML中)的变化值将反映设计时间的即时变化,而这正是我想要实现的目标。
我试图找到整个google / stack溢出和其他人的解决方案,但没有找到。到处都是在用户控件中创建依赖项属性的示例。
感谢您的时间。 任何帮助非常感谢。
编辑:根据Harlow Burgess的回答,设法在Silverlight中成为一个有效的例子。我把整个解决方案作为一个单独的答案。
答案 0 :(得分:2)
来自:http://msdn.microsoft.com/en-us/library/ms752914.aspx#setting_properties_data_binding
依赖项属性或DependencyObject类本身不具备 支持INotifyPropertyChanged 以生成通知 对数据绑定的DependencyObject源属性值的更改 操作。有关如何创建要使用的属性的更多信息 在数据绑定中,可以报告对数据绑定目标的更改,请参阅 数据绑定概述。
设计一个系统,当任何子属性(任何子属性,任何子属性,......)的任何属性发生变化时,通知整个对象图将是低效的。因此,当您需要在该属性更改时执行某些操作时,或者如果您确实希望在任何子属性更改时收到通知时,您应该使用数据绑定到特定属性,您应该实现 INotifyPropertyChanged 强>
How to: Implement Property Change Notification
示例:
public class DPGroup : DependencyObject, INotifyPropertyChanged
{
public static readonly DependencyProperty MyProperty1Property =
DependencyProperty.RegisterAttached(
"MyProperty1",
typeof(int),
typeof(DPGroup),
new PropertyMetadata(1));
public int MyProperty1
{
get { return (int)GetValue(MyProperty1Property); }
set { SetValue(MyProperty1Property, value); }
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
NotifyPropertyChanged(e.Property.Name);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class DPTest : UserControl
{
public static readonly DependencyProperty GroupProperty =
DependencyProperty.Register(
"Group",
typeof(DPGroup),
typeof(DPTest),
new PropertyMetadata(
new DPGroup(),
new PropertyChangedCallback(OnGroupPropertyChanged)
)
);
public DPGroup Group
{
get { return (DPGroup)GetValue(GroupProperty); }
set { SetValue(GroupProperty, value);}
}
static void OnGroupPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DPTest control = (DPTest)d;
DPGroup oldGroup = e.OldValue as DPGroup;
if (oldGroup != null)
{
oldGroup.PropertyChanged -=new PropertyChangedEventHandler(control.group_PropertyChanged);
}
DPGroup newGroup = e.NewValue as DPGroup;
if (newGroup != null)
{
newGroup.PropertyChanged +=new PropertyChangedEventHandler(control.group_PropertyChanged);
}
control.UpdateTextBox();
}
private void group_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
this.UpdateTextBox();
}
private void UpdateTextBox()
{
this.textBox1.Text = this.Group.MyProperty1.ToString();
}
private TextBox textBox1;
}
答案 1 :(得分:0)
好的,基于@Harlow Burgess的回答,我设法在Silverlight中成功运作。
基本上不同的是,在SL中,DependencyObject
类没有OnPropertyChanged
方法,所以在DPGroup
类中我们不能覆盖它,但我们可以用另一种方式附加此方法,通过:
new PropertyMetadata(1, OnPropertyChanged).
所以DPGroup
类看起来像这样:
public class DPGroup : DependencyObject, INotifyPropertyChanged
{
public static readonly DependencyProperty MyProperty1Property =
DependencyProperty.RegisterAttached(
"MyProperty1",
typeof(int),
typeof(DPGroup),
new PropertyMetadata(1, OnPropertyChanged));
public int MyProperty1
{
get { return (int)GetValue(MyProperty1Property); }
set { SetValue(MyProperty1Property, value); }
}
// static method invoked when MyProperty1 has changed value
static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DPGroup g = d as DPGroup;
if (g != null)
{
g.MyProperty1 = (int)e.NewValue;
// invoking event handler, to notify parent class about changed value of DP
if (g.PropertyChanged != null) g.PropertyChanged(g, null);
}
}
// event handler, for use in parent class
public event PropertyChangedEventHandler PropertyChanged;
}
父类,包含类型为DPGroup
的依赖项属性:
public partial class DPTest : UserControl
{
public static readonly DependencyProperty GroupProperty =
DependencyProperty.Register(
"Group",
typeof(DPGroup),
typeof(DPTest),
new PropertyMetadata(
new DPGroup(),
new PropertyChangedCallback(OnGroupPropertyChanged)
)
);
public DPGroup Group
{
get { return (DPGroup)GetValue(GroupProperty); }
set { SetValue(GroupProperty, value); }
}
// static method invoked when Group property has changed value
// here we need to attach event handler defined if DPGroup, so it will fire from inside Group property,
// when Group.MyProperty1 will change value
static void OnGroupPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DPTest control = (DPTest)d;
DPGroup oldGroup = e.OldValue as DPGroup;
// removing event handler from prevoius instance of DBGroup
if (oldGroup != null)
oldGroup.PropertyChanged -= new PropertyChangedEventHandler(control.group_PropertyChanged);
DPGroup newGroup = e.NewValue as DPGroup;
// adding event handler to new instance of DBGroup
if (newGroup != null)
newGroup.PropertyChanged += new PropertyChangedEventHandler(control.group_PropertyChanged);
DPTest g = d as DPTest;
if (g != null)
control.UpdateTextBox();
}
private void group_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
UpdateTextBox();
}
// here you can do anything with changed value Group.MyProperty1
private void UpdateTextBox()
{
this.textBox1.Text = this.Group.MyProperty1.ToString();
}
public DPTest()
{
InitializeComponent();
}
}
现在,DPTest
的XAML部分:
<UserControl x:Class="Silverlight_Workbench_2.DPTest"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Silverlight_Workbench_2"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" >
<Grid x:Name="LayoutRoot" Background="White">
<TextBox Height="23" HorizontalAlignment="Left" Margin="76,61,0,0"
x:Name="textBox1" VerticalAlignment="Top" Width="120" />
</Grid>
</UserControl>
最后,我们可以将DPTest
嵌入到任何控件的某些内容中,例如在另一个用户控件的Grid
中:
<UserControl x:Class="Silverlight_Workbench_2.DPTestMain"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Silverlight_Workbench_2"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
<Grid x:Name="LayoutRoot" Background="White">
<local:DPTest>
<local:DPTest.Group>
<!--here we can change value, and it will be reflected in design window
as a text in textBox1-->
<local:DPGroup MyProperty1="8"/>
</local:DPTest.Group>
</local:DPTest>
</Grid>
</UserControl>
就是这样,再次感谢Harlow Burgess的帮助!