I finally got my pivot control to work using MVVM in a wp8 app but I still have a question in regards to binding as thought as it works, and I could accept it as is, I'm not happy with the outcome and I'm trying to understand why this is happening. My DataContext, MainViewModel, contains multiple other ViewModels.
Scenario 1:
If I define the DataContext in the Grid (layout), and I assign the itemsSource for the pivot headers to QuickSearchTabs ViewModel and this get built ok but the listbox I have defined inside the pivotitem doesn't which is assigned the QuickSearchButtons ViewModel doesn't get built. Here is the xaml code:
<Grid x:Name="LayoutRoot" Background="Transparent" DataContext="{StaticResource MainViewModel}" >
<phone:Pivot x:Name="Pivot" ItemsSource="{Binding QuickSearchTabs}" FontSize="{StaticResource PhoneFontSizeSmall}" SelectedIndex="{Binding SelectedSearchTabIndex, Mode=TwoWay}">
<phone:Pivot.Title>
<TextBlock Text="My Search Options" />
</phone:Pivot.Title>
<phone:Pivot.HeaderTemplate>
<DataTemplate>
<ContentControl Content="{Binding Name}" />
</DataTemplate>
</phone:Pivot.HeaderTemplate>
<phone:Pivot.ItemTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding QuickSearchButtons}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Content="{Binding Name}" Grid.Row="0">
</Button>
<TextBlock Text="{Binding Description}" Grid.Row="1">
</TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</phone:Pivot.ItemTemplate>
</phone:Pivot>
</Grid>
Scenario 2:
If I define the DataContext in the Grid (layout) and define the same DataContext within the listbox tags, it will build my header and my listbox BUT it will call my viewModel which is assigned to the ItemsSource of the listbox, multiple times. To be exact, it will call it the same number of time as the number of pivots I have. Here is the xaml code:
<Grid x:Name="LayoutRoot" Background="Transparent" DataContext="{StaticResource CriteriaViewModel}" >
<phone:Pivot x:Name="Pivot" ItemsSource="{Binding QuickSearchTabs}" SelectedIndex="{Binding SelectedSearchTabIndex, Mode=TwoWay}" >
<phone:Pivot.Title>
<TextBlock Text="My Search Options" />
</phone:Pivot.Title>
<phone:Pivot.HeaderTemplate>
<DataTemplate>
<ContentControl Content="{Binding Name}"/>
</DataTemplate>
</phone:Pivot.HeaderTemplate>
<phone:Pivot.ItemTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding QuickSearchButtons}" DataContext="{StaticResource CriteriaViewModel}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Content="{Binding Name}" Grid.Row="0">
</Button>
<TextBlock Text="{Binding Description}" Grid.Row="1">
</TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</phone:Pivot.ItemTemplate>
</phone:Pivot>
</Grid>
As mentioned, this works, and it's not affecting me in anyway as the correct data is always displayed.
I can somehow see what's happening but why on earth would the ItemsSource be set for each of the defined pivot headers. Surely, the only important one is the one coming into visibility!
I don't know if Pivots are suppose to be used the way I'm using them. It seems, from what I've seen so far that normally a view is assigned to each PivotItem. This is not how I want my solution to work!
I just want numerous headers which are used to groups things in a specific manner and whatever is displayed under each is build dynamically but on the same view i.e. list of buttons and label.
Any ideas on how I could get scenario 1) to work and if I'm stuck with scenario 2, how to stop it from being triggered based on the number of pivot header items?
Thanks.
Problem solved!
The QuickSearchTabs was an observable collection of QuickSearchTab when it should have been an observable collection of ViewModel i.e. QuickSearchTabViewModel and within this viewModel, it will load the observable collection of relevant QuickSearchButtons for each of the tab.
Having a QuickSearchTabViewModel provides more flexibility and it will allow access to the current tab (header), and other relevant properties including everything maintain within each of these tabs such as, in my case the buttons.
Hope this helps.
Related
I have WinRT application with following GridView:
<GridView x:Name="RouteGrid"
ItemsSource="{Binding Routes}"
SelectedItem="{Binding SelectedRoute,
UpdateSourceTrigger=PropertyChanged,
Mode=TwoWay}"
SelectionMode="Single">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Width="300" Margin="4">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock FontWeight="Bold" Text="{Binding TermText}" />
<TextBlock Grid.Column="1" Text="{Binding ConnectionObjects.Count}" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
I want to show a button instead of the second textblock when ever the item is selected because I want to allow my users to navigate to another view when they've selected.
I would like to do it in pure XAML because that is for me the cleanest way but I have no idea how to bind to the IsSelected property of the GridViewItem.
In WPF I would bind the Visibility property of the TextBlock and the button with a BooleanToVisibilityConverter and RelativeSource to the AncestorType GridViewItem and its property but that's not working because WinRT does not know AncestorType :(
Thanks for help.
In my app, i have a longlistselector and i set the "DataContext = list" in the event PhoneApplicationPage_Loaded. Inside this longlistselector, i have this code:
<DataTemplate>
<StackPanel Margin="5,10" >
<Border BorderThickness="1" CornerRadius="5">
<Grid Margin="10,8" Tap="Grid_Tap_1" x:Name="gridPasta" Tag="{Binding Id_pasta}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="60"/>
</Grid.ColumnDefinitions>
<TextBlock Foreground="Black" HorizontalAlignment="Stretch" Text="{Binding Nm_pasta}" Grid.Column="0" TextWrapping="Wrap" VerticalAlignment="Top" TextTrimming="WordEllipsis" FontSize="24"/>
<Border Background="#E3F4FF" Grid.Column="1" CornerRadius="100">
<TextBlock Foreground="Black" Text="{Binding Qtde_pasta}" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="20"/>
</Border>
</Grid>
</Border>
</StackPanel>
</DataTemplate>
I want to set the background color of the specific Grid after i fill the LLS. I have search on internet about access LLS childs, but, nothing works. i have tried this link (Loop through longlistselector to get checkbox in itemtemplate), but the "SearchElement" not find the specific Grid.
My question is, how can i access this specific Grid after i fill the LLS?
Note: The specific Grid is known comparing the "Id_pasta" of the Grid.
Thanks for help.
You could add simple bool property (and implement PropertyChanged) to the class you're using for this datatemplate, bind it as background to the grid and use converter to convert it to desired backgroundcolor if true or false.
I have troubles with binding data to a Listbox to dynamically create ExpanderView.
I have used Listboxes in my Code before, so I'm not sure if the binding is really the problem. Am I setting the contents of ExpanderView wrong?
My Code so far in XAML:
<ListBox x:Name="Newsticker_Listbox">
<ListBox.ItemTemplate>
<DataTemplate>
<toolkit:ExpanderView Header="{Binding}" Expander="{Binding}" ItemsSource="{Binding}"
HeaderTemplate="{StaticResource CustomHeaderTemplate}"
ExpanderTemplate="{StaticResource CustomExpanderTemplate}"
ItemTemplate="{StaticResource CustomItemTemplate}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
the Templates:
<!--newsfeed templates-->
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="CustomHeaderTemplate">
<TextBlock Text="{Binding Title}" />
</DataTemplate>
<DataTemplate x:Key="CustomExpanderTemplate">
<Image Source="{Binding Subtitle}" />
</DataTemplate>
<DataTemplate x:Key="CustomItemTemplate">
<TextBlock Text="{Binding Title}" />
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
I'm binding with
ObservableCollection<news> newslist = new ObservableCollection<news>();
//populate
Newsticker_Listbox.ItemsSource = newslist;
news is a really simple object, it just stores some strings, which can be read out by news.Title, news.Subtitle etc
I've used the example from http://www.geekchamp.com/articles/expand-and-collapse-expanderview-inside-data-bound-listbox-via-code as basic for my code, I've just simplified it for my cause (mabye too much?)
Help is very appreciated, thank you all in advance
EDIT
This code works so far, but why does the solution with templates not work?
<ListBox x:Name="Newsticker_Listbox">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="10"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
</Grid.ColumnDefinitions>
<toolkit:ExpanderView>
<toolkit:ExpanderView.Header>
<TextBlock Text="{Binding Titel}" />
</toolkit:ExpanderView.Header>
<toolkit:ExpanderView.Expander>
<TextBlock Text="{Binding Untertitel}" />
</toolkit:ExpanderView.Expander>
<toolkit:ExpanderView.Items>
<TextBlock Text="{Binding Text}" />
</toolkit:ExpanderView.Items>
</toolkit:ExpanderView>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Remove your Header={Binding} and Expander={Binding} XAML code. It is overriding your custom HeaderTemplate and ExpanderTemplate.
You bound the Header and the Expander to the context of the application, which it doesn't really understand, so the binding resolved itself to nothing, so your ExpanderView displays nothing.
I have a strange problem with a combobox in a WinRT application running under Win 8 Release Preview. Here is a code snippet :
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{Binding Name, Mode=TwoWay}" VerticalAlignment="Center"/>
<ComboBox Grid.Column="1" ItemsSource="{Binding Source={StaticResource evtTypeRes}}" SelectedValuePath="ID" DisplayMemberPath="Name" SelectedValue="{Binding EventTypeID, Mode=TwoWay}" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
The ListView is backed by ObservableCollection list and the items implement INotifyPropertyChanged. The problem is that when I change the value of a combobox in the screen the value is changed not only for the particular row, but every row (the setter for the property is called on every object form the collection). This is not the case with the text box. What could be the reason for this strange behavior ?
Thanks in advance
I found the purpose of the IsSynchronizedWithCurrentItem attribute : value False solved my problem.
I am trying to bind a Listbox ItemSource to a collection of multiple Lists. i.e.
List PersonCollection
List Person
List Collection
Now I need to show items from both of these list. In wpf you could use HierarchicalDataTemplate i believe, but not sure how I can do it in windows phone 7. Tried with Blend and it generates the following data template.
<DataTemplate x:Key="PersonDataTemplate">
<Grid>
<StackPanel Margin="0,0,1,0" Orientation="Vertical" VerticalAlignment="Top">
<TextBlock Margin="0,0,1,0" TextWrapping="Wrap" Text="{Binding Person[0].Name}" d:LayoutOverrides="Width"/>
<TextBlock Margin="0,0,1,0" TextWrapping="Wrap" Text="{Binding Collection[0].Total}" d:LayoutOverrides="Width"/>
</StackPanel>
</Grid>
</DataTemplate>
<ListBox Height="300" x:Name="personList" ItemsSource="{Binding PersonCollection}" Margin="10,0" ItemTemplate="{StaticResource PersonDataTemplate}"/>
Is there another way I can do this? I have tried to set the DataContext of Textbox in DataTemplate to individual arrays but did not seem to work. Cant find anything similar on the net apart from the confirmation that HierarchicalDataTemplate is not supported in Windows Phone 7.
I have other ways to do but none elegant..
Thanks in advance.
Regards
I think your scenario can be solved with two level ListBoxes instead of Tree-Heirarchy. See if the below trick works. Now you will see Both of your inner collection side by side in a Grid which are two other ItemsControls(Or you can have ListBoxes)
<DataTemplate x:Key="PersonCollextionItem">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="0.5*"/>
</Grid.ColumnDefinitions>
<ItemsControl ItemsSource="{Binding ListPerson}" ItemTemplate="{StaticResource Templ1}" Grid.Column="0"/>
<ItemsControl ItemsSource="{Binding ListCollection}" ItemTemplate="{StaticResource Templ2}" Grid.Column="1"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="Templ1">
<TextBlock Margin="0,0,1,0" Text="{Binding Name}" />
</DataTemplate>
<DataTemplate x:Key="Templ2">
<TextBlock Margin="0,0,1,0" Text="{Binding Total}" />
</DataTemplate>
<ListBox Height="300" x:Name="personList" ItemsSource="{Binding PersonCollection}" Margin="10,0" ItemTemplate="{StaticResource PersonCollextionItem}"/>