WPF自定义控制和通过DependencyProperty公开属性

Gat*_*ndo 1 wpf controls dependencies properties

好的 - 我正在把我的头发拉出我认为是一个简单的场景:为双语使用创建一个包含两个附加属性的自定义标签(EnglishText,FrenchText).目前它的结构如下:

Public Class myCustomLabel
    Inherits System.Windows.Controls.Label

    Public myEnglishTextProperty As DependencyProperty = DependencyProperty.Register("myEnglishText", GetType(String), GetType(myCustomLabel), New PropertyMetadata("English", New PropertyChangedCallback(AddressOf TextChanged)))
    Public myFrenchTextProperty As DependencyProperty = DependencyProperty.Register("myFrenchText", GetType(String), GetType(myCustomLabel), New PropertyMetadata("Francais", New PropertyChangedCallback(AddressOf TextChanged)))

    Public Sub New()
        'This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class.
        'This style is defined in themes\generic.xaml
        DefaultStyleKeyProperty.OverrideMetadata(GetType(myCustomLabel), New FrameworkPropertyMetadata(GetType(myCustomLabel)))
    End Sub

    Public Property myEnglishText() As String
        Get
            Return MyBase.GetValue(myFrenchTextProperty)
        End Get
        Set(ByVal value As String)
            MyBase.SetValue(myFrenchTextProperty, value)
        End Set
    End Property

    Public Property myFrenchText() As String
        Get
            Return MyBase.GetValue(myFrenchTextProperty)
        End Get
        Set(ByVal value As String)
            MyBase.SetValue(myFrenchTextProperty, value)
        End Set
    End Property

    Private Sub TextChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
        If  DesignerProperties.GetIsInDesignMode(Me) = True Then
            Me.Content = myEnglishText
        Else
            If myUser.Language = "E" Then
                Me.Content = myEnglishText
            Else
                Me.Content = myFrenchText
            End If
        End If
    End Sub
End Class
Run Code Online (Sandbox Code Playgroud)

我的测试窗口网格xaml很简单:

<Grid>
        <my:myCustomLabel myEnglishText="English Text" myFrenchText="English Text" Height="25" Width="100" Background="Aqua" Foreground="Black"/>
</Grid>
Run Code Online (Sandbox Code Playgroud)

这似乎适用于开发环境 - 更改英语和法语文本会更改设计预览,并且当应用程序运行并打开测试窗口时它会起作用.但只是第一次 - 如果我第二次打开测试窗口,我会收到以下消息:

'myEnglishText'属性已由'myCustomLabel'注册.

我现在明白,如果我将依赖属性声明更改为共享,那么这个问题就会消失 - 但这会导致许多其他问题,例如需要共享回调函数 - 因此无法更新内容(需要用类来实例化). 我真正想要的是在更改英文和法文标签时要在设计时更新的内容属性.

有没有解决的办法?或者也许依赖属性过度杀戮我需要什么?

ito*_*son 7

您正在将依赖项属性注册为实例变量,并在实例构造函数中注册.因此,每次实例化控件时,它们都会再次注册,这会导致第二次出错.如您所知,依赖属性需要是静态(共享)成员:

Public Shared myEnglishTextProperty As DependencyProperty =   
  DependencyProperty.Register("myEnglishText", GetType(String), GetType(myCustomLabel),
  New PropertyMetadata("English", New PropertyChangedCallback(AddressOf TextChanged)))
Run Code Online (Sandbox Code Playgroud)

您可能需要在共享构造函数(类型初始化函数)中调用OverrideMetadata,而不是在实例构造函数中调用.

关于你需要共享回调的问题:是的,它会是,但回调的一个参数是标签实例.所以你可以将它转换为标签并调用实例方法:

private static void TextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  ((MyLabel)d).TextChanged();
}

private void TextChanged()
{
  // your code here
}
Run Code Online (Sandbox Code Playgroud)

(原谅C#语法)