ViewToViewModel - how to access property within the ViewModel

Topics: Questions
Nov 11, 2012 at 10:04 AM

Hello

I can't figure out how to access a [ViewToViewModel] decorated View property within the ViewModel. The help explains at UserControl explained and here how to define the property within the View. So how looks the code within the ViewModel to access such a property?

Could somebody provide an example?

Thanks in advance!
Nicolo

Coordinator
Nov 11, 2012 at 10:35 AM

Such a property is always mapped automatically for you. So, if you map a property on the view to a view model, they are automatically synchronized for you. In the vm, you only have to access the property on the viewmodel itself.

Nov 11, 2012 at 10:52 AM
Edited Nov 11, 2012 at 10:53 AM

If for example the View codebehind has:

[ViewToViewModel]
public bool MyDependencyProperty
{
   get { return (bool)GetValue(MyDependencyPropertyProperty); }
   set { SetValue(MyDependencyPropertyProperty, value); }
} 
public static readonly DependencyProperty MyDependencyPropertyProperty =
   DependencyProperty.Register("MyDependencyProperty", typeof(bool), typeof(MyControl), new UIPropertyMetadata(true));

Within the ViewModel i don't see the property. For example

class MyControlViewModel
{
    private MyControlViewModel()
    {
            MyDependencyProperty.... -> not accessible
    }
}
Coordinator
Nov 11, 2012 at 11:03 AM

You have to define the same property on the vm. If the names are different, you can specify that in the mapping as well.

Nov 11, 2012 at 1:51 PM
Edited Nov 11, 2012 at 1:53 PM

Thank you very much. It's unbelievable how you are responsive.

I defined the property within the ViewModel this way:

/// <summary>
/// Gets or sets the MyDependencyProperty property value and register it so it is known in the class.
/// </summary>
public bool MyDependencyProperty
{
    get { return GetValue<bool>(MyDependencyPropertyProperty); }
    set { SetValue(MyDependencyPropertyProperty, value); }
}
public static readonly PropertyData MyDependencyPropertyProperty = RegisterProperty("MyDependencyProperty", typeof(bool), false);

Is that correct? The ViewToViewModel attribute isn't necessary here? Anyway the property is reflecting from View to ViewModel.

Coordinator
Nov 11, 2012 at 2:24 PM
Edited Nov 11, 2012 at 2:24 PM

yes, this is correct. If you want, you can also use a different name for the property or mapping mode to control how the mapping should behave.

Nov 12, 2012 at 3:31 AM
Edited Nov 12, 2012 at 3:33 AM

Struggling with passing default value, because it is a non-static field:

[ViewToViewModel]
public ICollectionView TabItemsCollection
{
    get { return (ICollectionView)GetValue(TabItemsCollectionProperty); }
    set { SetValue(TabItemsCollectionProperty, value); }
}
public static readonly DependencyProperty TabItemsCollectionProperty =
   DependencyProperty.Register("TabItemsCollection", typeof(ICollectionView), typeof(MainWindow), new UIPropertyMetadata(tabCtrlMain.Items));

I want to submit the default value by 'new UIPropertyMetadata(tabCtrlMain.Items)', that is the TabItems of a TabControl. But with the code above the error message is 'cannot access non-static field tabCtrlMain in a static context'. The message is obviously.

Does this mean, we can't pass a default value for a reference type property?

Coordinator
Nov 15, 2012 at 8:50 AM

The field is static, so is the Register method. However, tabCtrlMain is not static (it's a member of the view). You cannot access non-static members in a static context. In other words, what you want is not possible.

Just keep the default value null. The view will automatically update the dependency property, and then it will automatically be mapped to the view model.

Nov 16, 2012 at 7:07 AM
Edited Nov 16, 2012 at 7:14 AM

I did add the tabitems at design-time:

<catel:TabControl x:Name="tabCtrlMain" Grid.Row="2" IsSynchronizedWithCurrentItem="True" ScrollViewer.CanContentScroll="True"
                          SelectedItem="{Binding SelectedTabItem}" >
    <TabItem Header="Start" IsSelected="{Binding IsTabStartSelected}" Tag="StartView"
                regions:RegionManager.RegionName="{x:Static Utils:RegionNames.StartRegion}"
                Style="{StaticResource MainTabItem}"/>

    <TabItem Header="Vorstudie" IsEnabled="{Binding CurrentVorstudie, Converter={StaticResource ReferenceToBooleanConverter}}" 
                IsSelected="{Binding IsTabVorstudieSelected}"
                regions:RegionManager.RegionName="{x:Static Utils:RegionNames.VorstudieRegion}" Tag="VorstudieView"
                Style="{StaticResource MainTabItem}" />
...

</catel:TabControl>

That's the cause why the DependencyProperty (TabItemsCollectionProperty) doesn't get a default-value at startup(?). What i want is to track the tabitems selection and if necessary to prevent leaving a tabitem (e.g. if it is dirty). That's not possible with the SelectionChanged event, because it raises when the current tabitem is already leaved. So i wanted to implement ICollectionView which makes this possible (see 'Selection' at http://marlongrech.wordpress.com/2008/11/22/icollectionview-explained and also http://joshsmithonwpf.wordpress.com/2009/09/04/how-to-prevent-a-tabitem-from-being-selected).

I found a solution with code behind (View), with the Window_Loaded event:

private void RibbonWindow_Loaded(object sender, RoutedEventArgs e)
{
    if (TabItemsCollection == null)
        TabItemsCollection = CollectionViewSource.GetDefaultView(tabCtrlMain.Items);
}

That's maybe not state of art, but i was not able to figure out how to populate the ItemsSource of the TabControl at runtime and get it's CollectionView.