为依赖属性创建代理

6
我正在尝试创建一个简单的依赖属性代理。我制作了一个自定义控件,它是一个文件选择器,由文本框(名称:"TextBox_FilePath")和显示打开文件对话框的按钮组成。
由于我正在制作可重用控件,我希望它具有"SelectedFilePath"属性。由于对于我的控件来说,Text属性似乎非常适合用作"SelectedFilePath"属性,因此我只想代理这些依赖属性。
我采取的第一种方法是:
public static readonly DependencyProperty SelectedFilePathProperty = TextBox.TextProperty;

public string SelectedFilePath
{
    get { return (string) this.TextBox_FilePath.GetValue(SelectedFilePathProperty); }
    set { this.TextBox_FilePath.SetValue(SelectedFilePathProperty, value); }
}

我尝试了一种方法,它能够工作,但在绑定到该属性时抛出异常。然后我找到了以下解决方案:

public static readonly DependencyProperty SelectedFilePathProperty =
    DependencyProperty.Register("SelectedFilePath", typeof (string), typeof (FilePicker), new PropertyMetadata(default(string)));

public string SelectedFilePath
{
    get { return (string) this.TextBox_FilePath.GetValue(SelectedFilePathProperty); }
    set { this.TextBox_FilePath.SetValue(SelectedFilePathProperty, value); }
}

这段代码可以工作,但我不知道为什么!?我在哪里指定了我想要文本框的text属性?

我错过了什么,以便简单地代理出该依赖属性?

编辑: 使用AddOwner的解决方案也不起作用,它会抛出一个异常,说“绑定只能应用于依赖属性”。 代码:

public static readonly DependencyProperty SelectedFilePathProperty =
    TextBox.TextProperty.AddOwner(typeof(FilePicker));

public string SelectedFilePath
{
    get { return (string)this.TextBox_FilePath.GetValue(SelectedFilePathProperty); }
    set { this.TextBox_FilePath.SetValue(SelectedFilePathProperty, value); }
}

我不明白什么?
编辑2: 对于其他有理解困难的人,我制作了一张小图
3个回答

2
第一种方法不起作用是因为属性只在TextBox注册,在另一个类中添加引用没有任何作用。
第二种方法仅创建了一个全新的字符串属性。
如果您真的想要重用TextBox.TextProperty,请调用AddOwner
例如:
public static readonly DependencyProperty SelectedFilePathProperty =
    TextBox.TextProperty.AddOwner(typeof(FilePicker));

注意,这个属性已经被注册为“Text”,所以你可能需要像以前一样创建一个新的属性并赋予你想要的名称。我还建议你使用元数据标志默认双向绑定,如果你希望拥有与TextBox.Text相同的绑定行为。

正如我所说,它以“Text”命名注册,因此您只能绑定到一个名为Text的属性,您创建的SelectedFilePath属性仅是在您的命令式代码中方便使用的包装器,绑定从未使用它。如果您想要不同的名称,请注册自己的属性。 - H.B.
请问您能否提供一个示例或者参考资料来说明如何实现这个功能? - GameScripting
@GameScripting:你已经在第二个代码块中完成了这个。没有必要重复使用 TextBox.Text,它并没有什么特殊的作用,可以使用自己的属性。 - H.B.
那么 AddOwner 应该放在哪里呢? - GameScripting
那么要“代理”一个属性,我只需声明自己的属性并将控件属性(TextBox.Text)绑定到我的属性上,这样一切都保持同步? - GameScripting
@GameScripting:没有什么魔法般的同步。你具体想做什么?如果你只是想要一些文本在你的控件中,你可以创建自己的属性并通过TemplateBinding将其绑定到ControlTemplate中的TextBox上。 - H.B.

1

这个解决方案有点棘手,但是有效。

考虑到这个用户控件:

<Grid>
    <StackPanel>
        <WpfApplication1:FilePicker SelectedFilePath ="{Binding MyProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        <TextBlock Text="{Binding MyProperty}" />
    </StackPanel>
</Grid>

以及它的视图模型:

public class MainWindowViewModel : INotifyPropertyChanged
{
    #region Implementation of INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string e)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(e));
    }

    #endregion

    private string _myProperty;
    public string MyProperty
    {
        get { return _myProperty; }
        set
        {
            _myProperty = value;
            OnPropertyChanged("MyProperty");
        }
    }
}

FilePicker控件的XAML:

<Grid>
    <TextBox x:Name="TextBox_FilePath" DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type WpfApplication1:FilePicker}}}" Text="{Binding SelectedFilePath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</Grid>

FilePicker控件的CodeBehind:

public partial class FilePicker : UserControl
{
    public FilePicker()
    {
        InitializeComponent();
    }

    /* private PROXY DP*/
    private static readonly DependencyProperty TextProperty =
        TextBox.TextProperty.AddOwner(typeof(FilePicker));

    /* public DP that will fire getter/setter for private DP  */
    public static readonly DependencyProperty SelectedFilePathProperty =
        DependencyProperty.Register("SelectedFilePath", typeof(string), typeof(FilePicker), new PropertyMetadata(default(string)));

    public string SelectedFilePath
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }
}

非常好用。


非常感谢,没有你的示例我就无法让它工作! - GameScripting

0

由于我对H.B.的回答存在理解上的问题,因此我制作了一张简单的图表来帮助自己更好地理解其背后的原理。以下是这个图表;

enter image description here

也许能帮助其他人 :)


现在我明白你没有理解的是什么了 :P - H.B.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接