【问题标题】:Create a proxy for a dependency property为依赖属性创建代理
【发布时间】:2012-06-11 15:01:41
【问题描述】:

我正在尝试创建一个简单的依赖属性代理。我做了一个自定义控件,它是一个文件选择器,它由一个文本框(名称:"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); }
}

我不明白什么?

EDIT2: 对于其他在理解答案方面有问题的人,我已经 a little graphic

【问题讨论】:

    标签: c# wpf xaml proxy dependency-properties


    【解决方案1】:

    第一种方法不起作用,因为该属性注册仅用于TextBox,在另一个类中添加引用不起作用。

    第二个只是创建了一个全新的字符串属性。

    如果你真的想重用TextBox.TextProperty,就调用AddOwner就可以了。

    例如

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

    (请注意,此属性已注册为"Text",因此您可能应该像以前那样创建一个具有您想要的名称的新属性。如果您愿意,我也建议set metadata flagsbind two-way by default具有与TextBox.Text 相同的绑定行为。)

    【讨论】:

    • 如我所说,它以“Text”名称注册,因此您只能绑定到名为Text 的属性,您创建的SelectedFilePath 属性只是为了方便您的命令式代码的包装器,绑定从不使用它。如果您想要不同的名称,请注册您自己的财产。
    • 能否请您提供一个示例或提供有关如何做到这一点的任何参考?
    • @GameScripting:您已经在第二个代码块中这样做了。没有真正需要重用TextBox.Text,它没有什么特别的,只是用你自己的财产去。
    • 那么AddOwner去哪儿了?
    • 所以要“代理”一个属性,我只需声明我自己的属性并将控制属性 (TextBox.Text) 绑定到我自己的属性,这样一切都会保持同步?
    【解决方案2】:

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

    鉴于此用户控制:

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

    像魅力一样工作。

    【讨论】:

    • 非常感谢,没有你的榜样,我就无法工作!
    【解决方案3】:

    由于我在理解 H.B.s answer 时遇到问题,所以我制作了一个小图,帮助我了解幕后发生的事情。在这里;

    也许它可以帮助别人:)

    【讨论】:

    • 现在我明白了你没有得到的东西:P
    猜你喜欢
    • 1970-01-01
    • 2013-03-26
    • 2010-11-10
    • 1970-01-01
    • 1970-01-01
    • 2011-06-09
    • 2011-05-29
    • 1970-01-01
    • 2011-07-07
    相关资源
    最近更新 更多