Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a proxy for a dependency property

I am trying to create a simple dependency property proxy. I made a custom control, it's a file picker, which is made off a textbox (name: "TextBox_FilePath") and a button showing the open file dialog.

As I am making a reusable control I'd like it to have a "SelectedFilePath" property. As the Text property seems to be perfect for my control to be the "SelectedFilePath" property, I'd just like to proxy these dependency property.

The first approach I made was:

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

which worked, but throwed an exception when trying to bind to that property. Then I came off with:

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

which does work, but I've got no idea why?! Where did I specify I wanted the text property of the textbox?

What am I missing to simply proxy out that dependency property?

EDIT: The solution with AddOwner doesn't work too, it throws an Excetion saying "binding can only be applied on a dependency property". Code:

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

What don't I understand?

EDIT2: For everybody else having issues understanding the answer, I've made a little graphic

like image 936
GameScripting Avatar asked Jun 11 '12 15:06

GameScripting


Video Answer


2 Answers

The first approach does not work because the property is registered only for the TextBox, adding a reference in another class does nothing.

The second one just creates a whole new string property.

If you really want to reuse the TextBox.TextProperty call AddOwner on it.

e.g.

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

(Note that this property is registered as "Text", so you probably should just create a new property with the name you want as you did already. I would also recommend to set metadata flags to bind two-way by default if you want to have the same binding behaviour as TextBox.Text.)

like image 153
H.B. Avatar answered Oct 02 '22 18:10

H.B.


This solution is a little tricky but works.

Given this user control:

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

And its viewmodel:

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

XAML for FilePicker control:

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

CodeBehind for FilePicker control:

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

Works like a charm.

like image 45
Jone Polvora Avatar answered Oct 02 '22 17:10

Jone Polvora