v.g.
v.g.

Reputation: 1076

How to get a property of a type when Binding

I have a type called "MyType" and my Pivot's ItemsSource is bound to an ObservableCollection property called "DataSource" inside the "myFirstVM" ViewModel. Inside "MyType" i have the property Title. As you can see from my XAML the TextBlock is bound to MyProperty. How to make it return the current item Title?

So for example, If i am on the second PivotItem, I need the Title of the second item in the DataSource collection

XAML:

<Grid x:Name="LayoutRoot">
    <Pivot Name="myPivot"
           SelectedItem="{Binding myFirstVM.SelItem, Mode=TwoWay}"
           ItemsSource="{Binding myFirstVM.DataSource}"
           ItemTemplate="{Binding myFirstVM.OtherTemplate}">
        <Pivot.HeaderTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding DataContext.myFirstVM.MyProperty, ElementName=myPivot}"/>
            </DataTemplate>
        </Pivot.HeaderTemplate>
    </Pivot>
</Grid>

myFirstVM code:

private ObservableCollection<MyType> _dataSource;
public ObservableCollection<MyType> DataSource
{
    get
    {
        if (this._dataSource == null)
        {
            this._dataSource = new ObservableCollection<MyType>();
        }
        return this._dataSource;
    }
    set { }
}

public string MyProperty 
{ 
    get
    {
        if (null != this.SelItem)
        {
            return this.SelItem.Title;
        }

        return "no title";
    } 
    set { }
}

private MyType _selItem;
public MyType SelItem
{
    get
    {
        return _selItem;
    }
    set
    {
        _selItem = value;

        RaisePropertyChanged("SelItem");
        RaisePropertyChanged("MyProperty");
    }
}

public ObservableCollection<MyOtherType> OtherDataSource
{
    get
    {
        if (null != this.SelItem)
        {
            return this.SelItem.OtherCollection;
        }
        else
        {
            return new ObservableCollection<MyOtherType>();
        }
    }
    set { }
}

private MyOtherType _selOtherItem;
public MyOtherType SelOtherItem
{
    get
    {
        return _selSegment;
    }
    set
    {
        _selSegment = value;

        RaisePropertyChanged("SelOtherItem");
        RaisePropertyChanged("PartsDataSource");
    }
}

public ObservableCollection<MyThirdType> ThirdDataSource
{
    get
    {
        if (null != this.SelOtherItem)
        {
            return this.SelOtherItem.ThirdCollection;
        }
        else
        {
            return new ObservableCollection<MyThirdType>();
        }
    }
    set { }
}

And these are my DataTemplates for the inner collections "OtherDataSource" and "ThirdDataSource", that are ListBoxes:

<DataTemplate x:Key="OtherTemplate">
    <ListBox DataContext="{Binding Source={StaticResource Locator}}"
             ItemsSource="{Binding myFirstVM.OtherDataSource}"
             ItemTemplate="{StaticResource ThirdTemplate}"
             SelectedItem="{Binding myFirstVM.SelOtherItem, Mode=TwoWay}">
    </ListBox>
</DataTemplate>

<DataTemplate x:Key="ThirdTemplate">
    <ListBox DataContext="{Binding Source={StaticResource Locator}}"
             ItemsSource="{Binding myFirstVM.ThirdDataSource}"
             ItemTemplate="{StaticResource FourthTemplate}">
    </ListBox>
</DataTemplate>

EDIT: I updated the question with the full ViewModel, and the DataTemplates, as sugested by @olitee. The problem with this approach as you can see is that in the second, and third dataTemplate I have ListBoxes. I am using one ViewModel for all the things. Any ideas?

Upvotes: 1

Views: 100

Answers (3)

v.g.
v.g.

Reputation: 1076

This is the right XAML implementation:

SelectedItem="{Binding myFirstVM.SelectedItem, Mode=TwoWay}"

and in the code behind instead of OnNotifyPropertyChanged the ViewModel needs to inherit ViewModelBase, part of MVVM Light then in the setter of SelectedItem property:

RaisePropertyChanged("SelectedItem");

Upvotes: 0

olitee
olitee

Reputation: 1683

You need to do a little extra work. Your ViewModel is not currently aware of which item is selected. You could create a new property called 'SelectedItem', and bind the Pivots' SelectedItem value.

Then you can access the Selected Item in code.

<Grid x:Name="LayoutRoot">
   <Pivot Name="myPivot"
       Tag="{Binding}"
       SelectedItem="{Binding myFirstVM.SelectedItem}"
       ItemsSource="{Binding myFirstVM.DataSource}"
       ItemTemplate="{Binding myFirstVM.ViewDataTemplate}">
   <Pivot.HeaderTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding DataContext.myFirstVM.MyProperty, ElementName=myPivot}"/>
        </DataTemplate>
   </Pivot.HeaderTemplate>
</Pivot>
</Grid>

Then your VM would look something like:

private ObservableCollection<MyType> _dataSource;
public ObservableCollection<MyType> DataSource
{
    get
    {
        if (this._dataSource == null)
        {
            this._dataSource = new ObservableCollection<MyType>();
        }
        return this._dataSource;
    }
    set { }
}

public string MyProperty 
{ 
    get
    {
        if (this.SelectedItem != null)
        {
            return this.SelectedItem.Title;
        }
        else
        {
            return null;
        }
    } 
}

private MyType _selectedItem;

public MyType SelectedItem
{ 
    get
    {
        return _selectedItem;
    } 
    set
    {
        _selectedItem = value;
        OnNotifyPropertyChanged("SelectedItem");
        OnNotifyPropertyChanged("MyProperty");
    }
}

Alternatively, if you're just wanting to fix up the text for presentation, and don't really require the SelectedItem in your VM, you could go with @Jehof's approach - but implement an IValueConvertor that performs the fix.

Upvotes: 1

Jehof
Jehof

Reputation: 35544

This should do the trick

<TextBlock Text="{Binding SelectedItem.Title, ElementName=myPivot}"/>

Bind the Text-Property to the SelectedItem property of the Pivot element. When the selected item of the Pivot changes the TextBlock should display the Title of the item.

Upvotes: 0

Related Questions