views:

1923

answers:

5

Hi, I have what I believe to be about one of the most simple cases of attempting to bind a view to a dependencyproperty in the view model. It seems that the initial changes are reflected in the view but other changes to the DP do not update the view's TextBlock. I'm probably just missing something simple but I just can't see what it is. Please take a look...

My XAML has a status bar on the bottom of the window. I want to bind to the DP "VRAStatus".

        <StatusBar x:Name="sbar" Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="2" 
               VerticalAlignment="Bottom" Background="LightBlue" Opacity="0.4" DockPanel.Dock="Bottom" >
            <StatusBarItem>
                <TextBlock x:Name="statusBar" Text="{Binding VRAStatus}" />
            </StatusBarItem>
            <StatusBarItem>
                <Separator Style="{StaticResource StatusBarSeparatorStyle}"/>
            </StatusBarItem>
        </StatusBar>

My viewmodel has the DP defined:

    public string VRAStatus
    {
        get { return (string)GetValue(VRAStatusProperty); }
        set { SetValue(VRAStatusProperty, value); }
    }

    // Using a DependencyProperty as the backing store for VRAStatus. 
    public static readonly DependencyProperty VRAStatusProperty =
        DependencyProperty.Register("VRAStatus", typeof(string), typeof(PenskeRouteAssistViewModel),new PropertyMetadata(string.Empty));

Then, in my code I set the DP:

        VRAStatus = "Test Message...";

Is there something obvious here that I am missing? In my constructor for the viewmodel I set the DP like this:

        VRAStatus = "Ready";

I never get the Test Message to display. Please Help.

thanks in advance! Bill

A: 

Try specifying the name of the DP with the Path flag in the binding like this:

<TextBlock x:Name="statusBar" Text="{Binding Path=VRAStatus}">
stevosaurus
Thanks stevosaurus! I had tried both with and without the Path and get the same result. It's curious, when I put in a breakpoint after the setting the property to "Test Message..." and hover over the "VRAStatus" name in the XAML, it does have the "Test Message..." in it as it's value.
Bill Campbell
Oh - and the DataContext is set correctly to the viewmodel.
Bill Campbell
Yeah, I wasn't sure if it would make a difference as I am just learning WPF myself. Seems strange that you are able to access the new value though. Have you tried specifying the binding mode as TwoWay? Something like {Binding Path=VRAStatus, Mode=TwoWay}
stevosaurus
Thanks Again! I do believe that two way binding is the default. I tried it anyhow with no change. I must be missing something really silly.
Bill Campbell
Hmm, does your PenskeRouteAssistViewModel inherit from DependencyObject? It seems that the textbox may not be getting notified of the property change, since it looks like the binding is setup correctly.
stevosaurus
Another good question - yes, it derives from a ViewModelBase class which is:public abstract class ViewModelBase : DependencyObject, INotifyPropertyChanged, IDisposableIf it didn't, then the GetValue and SetValue methods would not be defined.
Bill Campbell
[Binding Path=...] uses the default constructor and sets the path property of the binding object to the value. {Binding ...} calls the constructor that takes one argument, that argument being the path. http://msdn.microsoft.com/en-us/library/system.windows.data.binding.binding.aspx
Cameron MacFarland
A: 

Bill,

When and where do you set the DataContext? I had problems in the past that when I set the DataContext before the InitializeComponent, my Bindings never executed properly.

Also, for curiosity's sake: why do you use a DP in your ViewModel instead of just a Property?

Another good idea to think about. I create my viewmodel first and then pass that in to the view's contructor and I was setting the DataContext before calling InitializeComponent(). I moved it after it and no change.I thought that using a DP instead of a POCO was a good and simple way to provide an easily updateable field. The DP is supposed to be more memory efficient and so on. I can proabably make it a simple property and just implement the PropertyChanged stuff. I'm just confused as to why this doesn't work. I thought it was a major selling point for WPF.
Bill Campbell
You're also quite sure that the DataContext isn't set somewhere else too?
And you set the DataContext to the ViewModel instead of to the View? I.e:this.DataContext = myViewModel;Instead of:this.DataContext = this;
yes - here's my app.xaml.cs: // Create the ViewModel to which the main window binds var ViewModel = new ViewModel(dockManager); //Show the main window PRA vRAWindow = new PRA(ViewModel);and the view's constructor: public PRA(ViewModel vm) { viewModel = vm; DataContext = vm; InitializeComponent(); }We've been really careful not to set the DataContext in any other places. Please do let me know if you think of anything else and thanks for taking the time with a good response!
Bill Campbell
Sorry about the carriage controls not coming through in my last response - makes it rather hard to read.
Bill Campbell
I've been Googling around for this, and apparently there are more people who have difficulty binding their ViewModel to a DP:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/477433d0-76cc-40d2-be1d-ffe8e952e1fdYou just might want to consider using POCO instead. I think DP's are a bit OTT for what you're trying to achieve?http://stackoverflow.com/questions/291518/inotifypropertychanged-vs-dependencyproperty-in-viewmodel
Hi frances! Yes, I'm thinking that I might have to resort to POCO's at least temporarily but if I can't make DP's work as advertised it is going to be even more difficult to do more complex things, which is where I am headed. One of the major features of WPF is DP's and databinding so I'm confident that there is just some subtle thing that I am missing (like a TextBlock's Text isn't a DP and therefore doesn't support 2 way binding - which isn't true). But thanks for your thoughts on this!
Bill Campbell
A: 

Hi,

As it turns out things were a little more complicated than I had thought (like, when is that NOT the case :) My RibbonControl was in a UserControl to get all of that XAML out of the MainWindow. It was the fact that it was in a UserControl that made it work differently with the ViewModel. I don't know why - probably one of those mysteries that won't ever be solved. But by putting my RibbonControl directly on the MainWindow, everything works as expected - both with a DP and a C# Property. Interesting. (Wish I could get back those two days of my life!)

thanks, Bill

Bill Campbell
A: 

Try to specify the UpdateSourceTrigger property of the Binding:

<StatusBar x:Name="sbar" Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="2" 
           VerticalAlignment="Bottom" Background="LightBlue" Opacity="0.4" DockPanel.Dock="Bottom" >
        <StatusBarItem>
            <TextBlock x:Name="statusBar" Text="{Binding VRAStatus, UpdateSourceTrigger=PropertyChanged}" />
        </StatusBarItem>
        <StatusBarItem>
            <Separator Style="{StaticResource StatusBarSeparatorStyle}"/>
        </StatusBarItem>
    </StatusBar>
juanjo.arana