0

New to WPF. I am creating UserControls that need read access to the ViewModel state to do their thing. I currently use the following technique:

public partial class ControlBar : UserControl
{

    private static readonly DependencyProperty URLProperty =
        DependencyProperty.Register("URL", typeof(string), typeof(ControlBar),
        new UIPropertyMetadata(null));

    public ControlBar()
    {
        InitializeComponent();

        SetBinding(URLProperty, "CurrentPage.URL");

        Pin.Click += Pin_Click;       
    }

    private void Pin_Click(object sender, RoutedEventArgs e)
    {
        var URL = (string)GetValue(URLProperty);

    }
}

Is this the correct way and is it not overkill to set up a long-term binding for each variable I need access to? Or can you do something like:

GetValue(new Path("CurrentPage.URL..... 

I made up the above obviously.

Thanks!

Jamona Mican
  • 1,574
  • 1
  • 23
  • 54
  • Why not specify the bindings in the XAML? You'd need to implement the DP fully for that to work (getter/setter) – Steve Greatrex Feb 24 '12 at 20:14
  • I could set-up the binding in XAML. It's not the set-up that concerns me. It's the need for 'placeholder' DependencyProperties in each user control, for the sole purpose of accessing the viewmodel. These DPs are private so they have no other use. – Jamona Mican Feb 24 '12 at 20:21
  • I would suggest that if you are writing a custom control that relies on view model properties, those *should* be exposed as publicly settable properties on the control – Steve Greatrex Feb 24 '12 at 20:24
  • Why? If there is a piece of information that 29 entities need to access to do their work, why would all 29 entities expose that same information publicly. e.g. a flag for "is user logged in?" Seems like pollution. It should be exposed by a single entity... Those 29 should only expose things which a parent can use to customize their individual behavior. – Jamona Mican Feb 24 '12 at 20:53
  • Without knowing more about the specifics I can't really comment, but if you are writing a control that changes its behaviour based on a value then I don't think it is unreasonable for the control to expose that value. – Steve Greatrex Feb 24 '12 at 21:03
  • Well in any case... There is no other way to get the data from the viewmodel I'm starting to gather. I need a DP + binding? – Jamona Mican Feb 24 '12 at 21:05
  • 1
    You could try a couple of other things, though I've not tried them myself. One would be to react to the controls `DataContext` property being changed (this will be set to the view model instance). Another might be to use a single property set to the value of the view model in its entirety and then use the value to pull off any properties you need - it's still some binding, but not one for each value. – Steve Greatrex Feb 24 '12 at 21:09
  • Thanks. I'll give those a try. – Jamona Mican Feb 24 '12 at 21:39

1 Answers1

4

In general data-binding is the way to go. However sometimes when you are creating controls that have view-specific concerns for which data-binding will not be appropriate.

In those cases you will want to be able to interact with the DependencyProperty to set it and know when it changes. I have been following a pattern that I picked up from a Charles Petzold article in MSDN magazine.

My answer to another question shows the pattern for creating a DependencyProperty for a UserControl Stack Overflow: Dependency Property In WPF/SilverLight

Again, data-binding to a view model will likely solve your problem, but a DependencyProperty may come in useful depending on the situation.

Update in response to comment:

In many situations you can data bind your in a UserControl without using a DependencyProperty. For example if you have a TextBlock that displays a name you would put a TextBlock in the XAML of the UserControl

<TextBlock Text="{Binding Path=NameString}" />

In the view model which is present in the DataContext you would have a property NameString and if the TextBlock is to update the display when the NameString property changes the view model should implement INotifyPropertyChanged and the property should fire the PropertyChanged event with the name of the property sent along with the event.

protected string _NameString;
public string NameString
{
    get { return _NameString; }
    set { _NameString = value: Notify("NameString"); }
}

Where Notify is a method that checks the PropertyChanged event for null and sends the event if not null.

This works well if everywhere that you want to use the UserControl has a view model with a Name property. The great thing is that the UserControl can pick up on the DataContext of wherever it is hosted and bind to an external view model.

When you want to start binding the same UserControl to different properties is one place that you may want to use a DependencyProperty. In that case you could make a UserControl with a DependencyProperty and bind it to different properties

<my:SampleControl NameString="{Binding Path=GivenName}" />
<my:SampleControl NameString="{Binding Path=FamilyName}" />

And then have an internal view model that the DependencyProperty change handler updates when the bound property changes.

Update: No DependencyProperty or binding

You can always add an ordinary C# property to the UserControl and pass the data in that way.

public MyClass Data { get; set; }

Then in the code-behind of the UserControl you can simply use the property:

if (this.Data != null)
{
    this.textBox1.Text = Data.NameString;
}

Update in response to comment:

Another way to access the view model in code is to cast the DataContext to your view model type:

MyClass data = this.DataContext as MyClass;
if (data != null)
{
    // do something
    this.textBox1.Text = data.NameString;
}
Community
  • 1
  • 1
Doug Ferguson
  • 2,538
  • 2
  • 16
  • 23
  • "Again, data-binding to a view model will likely solve your problem, but a DependencyProperty may come in useful depending on the situation." Is this sentence suggesting you can databind without using a DP? That's what I'm looking for. How is it done? – Jamona Mican Feb 24 '12 at 21:00
  • I added more details to the answer in response to your comment. – Doug Ferguson Feb 24 '12 at 23:37
  • Thanks Doug. I have given you an upvote for your expanded answer but it still doesn't help me rewrite the code above so that it does not rely on a dependencyproperty. SetBinding needs a DP so how can I get the value from the viewmodel, IN CODE, without a DP? – Jamona Mican Feb 25 '12 at 01:00
  • Maybe it's a long day and my brain is not working but that still doesn't really fit the bill. My usercontrol has inherited the datacontext which is bound to the viewmodel, so there should be an easy way to access the viewmodel state in code, say in the constructor of my usercontrol. Guess I'll stick to DPs for each VM value I need. – Jamona Mican Feb 25 '12 at 02:41
  • 1
    Try casting the DataContext to the type of the view model and that should give access to the data. – Doug Ferguson Feb 25 '12 at 03:25
  • You may want to add that to your main answer and I'll accept it, as that's the closest to what I'm looking for so far. Not ideal of course but will use it for now. Thx – Jamona Mican Feb 25 '12 at 10:18