Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/259.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在单独的类中收集的依赖项属性_C#_Wpf_Silverlight_Xaml_Dependency Properties - Fatal编程技术网

C# 在单独的类中收集的依赖项属性

C# 在单独的类中收集的依赖项属性,c#,wpf,silverlight,xaml,dependency-properties,C#,Wpf,Silverlight,Xaml,Dependency Properties,我的问题与Silverlight有关(但我想WPF也是如此) 基本上,我知道如何在用户控件中创建依赖项属性以及如何使其工作。但我试图做的,但没有成功的是:在一个类中创建依赖属性(或多个),这个类将成为我的用户控件的依赖属性 换言之: // my UserControl public class DPTest : UserControl { // dependency property, which type is a class, and this class will be holdi

我的问题与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.MyProperty1
)的成员更改了它的值。我设法在运行时实现了这一点,例如通过使用
DPGroup
类中定义的事件处理程序,但这在xaml的设计时不起作用

<Grid x:Name="LayoutRoot" Background="White">
    <local:DPTest>
        <local:DPTest.Group>
            <local:DPGroup MyProperty1="2"/>
        </local:DPTest.Group>
    </local:DPTest>
</Grid>
我看到一些类似于
UIElement.RenderTransform
(假设它是我的
属性)的东西,例如
ScaleTransform

<Grid x:Name="LayoutRoot" Background="White">
    <Grid.RenderTransform>
        <ScaleTransform ScaleX="0.4"/>
    </Grid.RenderTransform>      
</Grid>

ScaleX
类似于
MyProperty1
。不同之处在于,
ScaleX
(以XAML为单位)的值的变化将反映设计时的即时变化,而这正是我试图实现的

我试图在整个google/stack overflow和其他方面找到解决方案,但没有找到。到处都是在用户控件中创建依赖项属性的示例

谢谢你抽出时间。 非常感谢您的帮助

编辑:根据哈洛·伯吉斯的回答,a成功地在Silverlight中制作了一个工作示例。我将整个解决方案作为一个单独的答案放在下面。

来源:

依赖项属性或DependencyObject类不是本机的 支持INotifyPropertyChanged以生成通知 数据绑定的DependencyObject源属性值的更改数量 操作。有关如何创建要使用的属性的详细信息,请参见 在可以报告数据绑定目标更改的数据绑定中,请参见 数据绑定概述

如果设计一个系统,在任何子属性(任何子属性、任何子属性等)的任何属性发生更改时通知整个对象图,则效率低下。因此,当需要在属性更改时执行某些操作时,或者如果确实希望在任何子属性更改时收到通知,则应该使用数据绑定到特定属性,您应该实现INotifyPropertyChanged

例如:

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;

}  

好的,基于@Harlow Burgess answer,a成功地在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>

就这些,再次感谢哈洛·伯吉斯的帮助

感谢您的回答,但是在哪里实现INotifyPropertyChanged
?在用户控件
DPTest
或包含属性的类(
DPGroup
)上。我想,我尝试了第二种选择,但没有成功。谢谢你指出了一个效率低下的问题。我会给+1,但我还不能投票:)在DependencyObject上实现InotifyProperty更改。从UserControl订阅该通知。参见上面的示例代码。你不必投票,只要把它标记为答案,如果它对你有帮助的话。谢谢!尽管这段代码只在WPF中工作(做了一些修改),但我理解了一般的概念,并且能够在Silverlight中重现这段代码。为了能够在WPF中运行它,我需要a)从两个类中的DPs中删除
只读
,b)在我的环境中,我在XAML中实例化时出现异常
:无法将
属性的默认值绑定到特定线程。然后,我让DBGroup继承自
Freezable
(不是从DependencyObject继承的),就像这里写的那样:这就开始工作了。谢谢
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();

    }
}  
<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>
<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>