WP8 xaml causes "element is already child of another element" - xaml

I am following MSDN examples to add a settings page to my first Windows Phone 8 application (warning - I am completely new to XAML, I'm a C++ guy).
The xaml looks like this:
<phone:PhoneApplicationPage
x:Class="PicoSDU.AppSettings"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PicoSDU"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d"
shell:SystemTray.IsVisible="True">
<phone:PhoneApplicationPage.Resources>
<local:AppSettings x:Key="PicoSettings"></local:AppSettings>
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="PicoSDU" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="Settings" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel Margin="30,0,0,0">
<TextBlock Height="36" HorizontalAlignment="Left" Margin="0,0,0,0" Name="txtIpAddress" Text="IP Address" VerticalAlignment="Top" Width="169" />
<TextBox Name="tbIpAddress" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" Width="274"
Text="{Binding Source={StaticResource PicoSettings}, Path=IpSetting, Mode=TwoWay}"/>
<TextBlock Height="36" HorizontalAlignment="Left" Margin="0,0,0,0" Name="txtPort" Text="Port Number" VerticalAlignment="Top" Width="169" />
<TextBox Name="tbPort" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" Width="274"
Text="{Binding Source={StaticResource PicoSettings}, Path=PortSetting, Mode=TwoWay}"/>
<TextBlock Height="36" HorizontalAlignment="Left" Margin="0,0,0,0" Name="txtSysId" Text="System ID" VerticalAlignment="Top" Width="169" />
<TextBox Name="tbSysId" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" Width="274"
Text="{Binding Source={StaticResource PicoSettings}, Path=SysIdSetting, Mode=TwoWay}"/>
<TextBlock Height="36" HorizontalAlignment="Left" Margin="0,0,0,0" Name="txtWsId" Text="Station ID" VerticalAlignment="Top" Width="169" />
<TextBox Name="tbWsId" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" Width="274"
Text="{Binding Source={StaticResource PicoSettings}, Path=WsIdSetting, Mode=TwoWay}"/>
</StackPanel>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
So, pretty simple. four text boxes. It rendered perfectly OK until I added the resource clause
<phone:PhoneApplicationPage.Resources>
<local:AppSettings x:Key="PicoSettings"></local:AppSettings>
</phone:PhoneApplicationPage.Resources>
As soon as I add that the XAML parser throws a wobbler and the root PhoneApplicationPage gets the old blue squiggly and reports our favourite "element is already the child of another element" error. If I remove the resource clause, that error goes away and the xaml renders, but of course the textbox bindings then all throw an error because they cannot see their resources.
I've been googling this the last three hours and I can't see what's wrong, and none of the answers I've found here and elsewhere seem to fit. Can some kind soul show me the blindingly stupid thing I've done and please put me out of my misery?
Edit
Here's the AppSettings class. It's just the Microsoft code sample, hacked into the code-behind:
namespace PicoSDU
{
public partial class AppSettings : PhoneApplicationPage
{
// Our settings
IsolatedStorageSettings settings;
// The key names of our settings
const string IpSettingKeyName = "IpSetting";
const string SysIdSettingKeyName = "SysIdSetting";
const string WsIdSettingKeyName = "WsIdSetting";
const string PortSettingKeyName = "PortSetting";
// The default value of our settings
const string IpSettingDefault = "81.179.24.51";
const string SysIdSettingDefault = "1";
const string WsIdSettingDefault = "511";
const string PortSettingDefault = "1846";
public AppSettings()
{
InitializeComponent ();
try
{
settings = IsolatedStorageSettings.ApplicationSettings;
}
catch (System.IO.IsolatedStorage.IsolatedStorageException e)
{
// handle exception
}
}
public bool AddOrUpdateValue(string Key, Object value)
{
bool valueChanged = false;
// If the key exists
if (settings.Contains(Key))
{
// If the value has changed
if (settings[Key] != value)
{
// Store the new value
settings[Key] = value;
valueChanged = true;
}
}
// Otherwise create the key.
else
{
settings.Add(Key, value);
valueChanged = true;
}
return valueChanged;
}
public T GetValueOrDefault<T>(string Key, T defaultValue)
{
T value;
// If the key exists, retrieve the value.
if (settings.Contains(Key))
{
value = (T)settings[Key];
}
// Otherwise, use the default value.
else
{
value = defaultValue;
}
return value;
}
public void Save()
{
settings.Save();
}
public string IpSetting
{
get
{
return GetValueOrDefault<string>(IpSettingKeyName, IpSettingDefault);
}
set
{
if (AddOrUpdateValue(IpSettingKeyName, value))
{
Save();
}
}
}
public string SysIdSetting
{
get
{
return GetValueOrDefault<string> ( SysIdSettingKeyName, SysIdSettingDefault );
}
set
{
if (AddOrUpdateValue ( SysIdSettingKeyName, value ))
{
Save ();
}
}
}
public string WsIdSetting
{
get
{
return GetValueOrDefault<string> ( WsIdSettingKeyName, WsIdSettingDefault );
}
set
{
if (AddOrUpdateValue ( WsIdSettingKeyName, value ))
{
Save ();
}
}
}
public string PortSetting
{
get
{
return GetValueOrDefault<string> ( PortSettingKeyName, PortSettingDefault );
}
set
{
if (AddOrUpdateValue ( PortSettingKeyName, value ))
{
Save();
}
}
}
}
}

Your code is quite bizzare. You are trying to embed one Page (your AppSettings class inherits from PhoneApplicationPage) into another. A much better approach would be to use the MVVM pattern.
Do not make the AppSettings inherit from PhoneApplicationPage and make it into a ViewModel. More info at http://msdn.microsoft.com/en-us/library/windowsphone/develop/gg521153(v=vs.105).aspx

Related

UWP/C# ItemsControl Multiple Boxes?

I have had a lot of help so far with creating the correct formatting for an ItemsControl panel and appreciate this communities help so far with helping me troubleshoot coding issues.
Im currently at a rather small hurdle where im trying to figure out how to create multiple boxes within the same ItemsControl. Currently the overall view looks like this:
Im a little stumped and would just like a little guidance really as to where to put the other XAML lines.
I need it to look like this:
Here is my code currently (its all nested within a Frame):
<ItemsControl ItemsSource="{StaticResource userDataCollection}" Margin="40,40,40,725" Width="Auto" Height="310">
<!-- Changing Orientation of VirtualizingStackPanel -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- Change header for ItemsControl -->
<ItemsControl.Template>
<ControlTemplate>
<Border Background="{StaticResource CustomAcrylicDarkBackground}">
<StackPanel>
<TextBlock Text="Accounts At A Glance" FontSize="28" Foreground="#b880fc" Padding="12"/>
<ItemsPresenter/>
</StackPanel>
</Border>
</ControlTemplate>
</ItemsControl.Template>
<!-- Template for each card-->
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Width="240" Height="240" Background="Gray" Margin="30,0,0,0" VerticalAlignment="Center" Padding="4">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Name}" HorizontalAlignment="Center" TextAlignment="Center" Width="220" FontSize="24"/>
<TextBlock Grid.Row="1" Text="{Binding PayDate}" HorizontalAlignment="Center" TextAlignment="Center" Width="220" FontSize="14" />
<TextBlock Grid.Row="2" Text="{Binding NumberOfItems}" HorizontalAlignment="Center" TextAlignment="Center" Width="220" FontSize="14"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I really apologise for this, im trying to learn as much as i can as i go. Im mainly stuggling with the XAML formatting and incorperating learning material into my project :/ Any help would be amazing
I have an alternative approach for your problem. This uses "semi" MVVM approach (browse through the net and study this pattern).
MainPageViewModel.cs
public class MainPageViewModel : INotifyPropertyChanged
{
private ObservableCollection<User> _userCollection;
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<User> UserCollection
{
get => _userCollection;
set
{
_userCollection = value;
NotifyProperyChanged();
}
}
private void NotifyProperyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void LoadData()
{
UserCollection = new ObservableCollection<User>
{
new User
{
Name = "John Doe",
PayDate = DateTime.Now,
NumberOfItems = 1
},
new User
{
Name = "John Doe 2",
PayDate = DateTime.Now,
NumberOfItems = 1
},
new User
{
Name = "John Doe 3",
PayDate = DateTime.Now,
NumberOfItems = 1
},
};
}
}
The view (got rid of some styling temporarily):
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:App1.ViewModels"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
Loaded="MainPage_OnLoaded">
<Page.DataContext>
<vm:MainPageViewModel/>
</Page.DataContext>
<Grid>
<ScrollViewer>
<ItemsControl ItemsSource="{Binding UserCollection, Mode=TwoWay}" Margin="15" Width="Auto" Height="310">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- Template for each card-->
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Width="200" Height="100" Background="Gray" Margin="15,0,0,0" VerticalAlignment="Center" Padding="4">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Name}" HorizontalAlignment="Center" TextAlignment="Center" Width="220" FontSize="24"/>
<TextBlock Grid.Row="1" Text="{Binding PayDate}" HorizontalAlignment="Center" TextAlignment="Center" Width="220" FontSize="14" />
<TextBlock Grid.Row="2" Text="{Binding NumberOfItems}" HorizontalAlignment="Center" TextAlignment="Center" Width="220" FontSize="14"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Page>
View's code-behind:
namespace App1
{
public sealed partial class MainPage
{
public MainPage()
{
this.InitializeComponent();
}
public MainPageViewModel VM => (MainPageViewModel) DataContext;
private void MainPage_OnLoaded(object sender, RoutedEventArgs e)
{
VM.LoadData();
}
}
}
Output:
Next steps:
Apply your styling. Study how to limit grid columns.
Improve the code
further, in MVVM you shouldn't really have implementations on the
code-behind, so study for ICommand, Microsoft.Xaml.Interactivity
Hope this helps.
It perfect now.
Im an idiot.
I essentially needed to seperate the information presented within the UserData.cs Class. I didnt understand how the information was being read but understand it now. The XAML has been left untouched as it works currently for what i need. It will be update to follow the MVVM format as mentioned by Mac. Here is the UserData.CS class located inside a data folder:
using System.Collections.ObjectModel;
namespace BudgetSheet.Data
{
public class UserData
{
public string Name { get; set; }
public string PayDate { get; set; }
public string NumberOfItems { get; set; }
}
class UserDataCollection : ObservableCollection<UserData>
{
public UserDataCollection()
{
// Placeholder, needs to be replaced with CSV or Database information
this.Add(new UserData()
{
Name = "Selected Username",
PayDate = "Friday",
NumberOfItems = "ItemAmount Placeholder"
});
// Placeholder for user 2
this.Add(new UserData()
{
Name = "Selected Username 2",
PayDate = "Friday 2",
NumberOfItems = "ItemAmount Placeholder 2"
});
// Placeholder for user 3
this.Add(new UserData()
{
Name = "Selected Username 3",
PayDate = "Friday 3",
NumberOfItems = "ItemAmount Placeholder 3"
});
}
}
}
Here is what it was before hand and why there were issues with information display:
using System.Collections.ObjectModel;
namespace BudgetSheet.Data
{
public class UserData
{
public string Name { get; set; }
public string PayDate { get; set; }
public string NumberOfItems { get; set; }
}
class UserDataCollection : ObservableCollection<UserData>
{
public UserDataCollection()
{
// Placeholder, needs to be replaced with CSV or Database information
this.Add(new UserData()
{
Name = "Selected Username",
});
// Placeholder for user selected PayDate
this.Add(new UserData()
{
PayDate = "Friday",
});
// Placeholder for user selected PayDate
this.Add(new UserData()
{
NumberOfItems = "ItemAmount Placeholder"
});
}
}
}
This solution does not provide much flexibility currently but it works for the formatting. Marking as resolved to close the ticket

How to hide top part of hamburger menu in the XAML Navigation Sample?

In the Windows UWP XAML Navigation sample from git hub, how can you hide the very top part of the hamburger menu flyout that obscures the section title?
Currently it renders like this so there is a strip that hides the section title of the page.
How can I get it to look like this? So the Section title is not obscured when I open the menu.
I tried playing with the z-index of the page header, but it had no effect. The hamburger menu always renders over top everything else.
Just check the Microsoft weather app for windows 10, I think it's more like there is a region out of the SplitView control, which is to hold like "hamburger button", "back button", "commandbar", and "AutoSuggestBox".
Here I wrote a sample:
<Page.Resources>
<local:BoolToVisiableConverter x:Key="visiblecvt" />
<local:BackgroundConverter x:Key="backgroundcvt" />
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="15*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="{Binding ElementName=listmenu, Path=SelectedItem.MenuText, Converter={StaticResource backgroundcvt}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Button BorderThickness="0" Background="LightBlue" Click="Button_Click_Pane" Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Button.Content>
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="24" />
</Button.Content>
</Button>
<Button BorderThickness="0" Background="Transparent" Click="Button_Click_Back" Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Button.Content>
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="24" />
</Button.Content>
</Button>
<TextBlock FontSize="24" Grid.Column="2" x:Name="title" VerticalAlignment="Center" Text="{Binding ElementName=listmenu, Path=SelectedItem.MenuText}" />
<CommandBar Grid.Column="3" Background="Transparent" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Visibility="{Binding ElementName=title, Path=Text, Converter={StaticResource visiblecvt}}">
<CommandBar.Content>
<Grid />
</CommandBar.Content>
<AppBarButton Icon="Accept" FontSize="24" Label="Accept" />
<AppBarButton Icon="Cancel" FontSize="24" Label="Cancel" />
</CommandBar>
<AutoSuggestBox Grid.Column="4" VerticalAlignment="Center" HorizontalAlignment="Stretch" IsSuggestionListOpen="True" />
</Grid>
<SplitView Grid.Row="1" x:Name="RootSpiltView" OpenPaneLength="300" CompactPaneLength="50" DisplayMode="CompactOverlay">
<SplitView.Pane>
<ListView x:Name="listmenu" ItemsSource="{x:Bind menu}" SelectionChanged="ListView_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding MenuIcon}" FontFamily="Segoe MDL2 Assets" FontSize="24" VerticalAlignment="Center" />
<TextBlock Text="{Binding MenuText}" Margin="15" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</SplitView.Pane>
<SplitView.Content>
<Frame x:Name="splitviewContent" Navigated="splitviewContent_Navigated" />
</SplitView.Content>
</SplitView>
</Grid>
code behind:
private ObservableCollection<NavigationItem> menu = new ObservableCollection<NavigationItem>();
public MainPage()
{
this.InitializeComponent();
this.Loaded += MainPage_Loaded;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
menu.Clear();
menu.Add(new NavigationItem { PageLink = typeof(Page1), MenuText = typeof(Page1).Name, MenuIcon = "\xE715" });
menu.Add(new NavigationItem { PageLink = typeof(Page2), MenuText = typeof(Page2).Name, MenuIcon = "\xE716" });
menu.Add(new NavigationItem { PageLink = typeof(Page3), MenuText = typeof(Page3).Name, MenuIcon = "\xE722" });
menu.Add(new NavigationItem { PageLink = typeof(Page4), MenuText = typeof(Page4).Name, MenuIcon = "\xE72D" });
}
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
listmenu.SelectedIndex = 0;
}
private void Button_Click_Pane(object sender, RoutedEventArgs e)
{
this.RootSpiltView.IsPaneOpen = !this.RootSpiltView.IsPaneOpen;
}
private void Button_Click_Back(object sender, RoutedEventArgs e)
{
if (splitviewContent.CanGoBack)
{
splitviewContent.GoBack();
}
}
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var naviitem = listmenu.SelectedItem as NavigationItem;
splitviewContent.Navigate(naviitem.PageLink);
}
private void splitviewContent_Navigated(object sender, NavigationEventArgs e)
{
var page = splitviewContent.CurrentSourcePageType.Name;
switch (page)
{
case "Page1":
listmenu.SelectedIndex = 0;
break;
case "Page2":
listmenu.SelectedIndex = 1;
break;
case "Page3":
listmenu.SelectedIndex = 2;
break;
case "Page4":
listmenu.SelectedIndex = 3;
break;
}
}
The NavigationItem class and two converters:
public class NavigationItem
{
public string MenuIcon { get; set; }
public string MenuText { get; set; }
public Type PageLink { get; set; }
}
public class BoolToVisiableConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var text = (string)value;
if (text == "Page1")
{
return Visibility.Visible;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
public class BackgroundConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var text = (string)value;
if (text == "Page1")
{
return "#FFFFC0CB";
}
return "#00000000";
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
I didn't follow to the official XAML Navigation sample to wrote this code, here my sample renders like this:
#Henk Holterman's comment also makes sense. In the official sample, the title is part of the page content. For different page, the title may have different size. But in Weather app, the title is separated from the content, so it will be easy to achieve.

TwoWay Data Binding with MVVM Light on Windows Phone 8.1

I'm trying to create a custom Button with ListPickerFlyout using MVVM. The result that i wanna reach is something like that:
custom Button with ListPickerFlyout
My problem is how to bind the SelectedItem from ListPickerFlyout to the content TextBlock.
I'm using MVVM Light Windows Phone 8.1 (Store Appp).
My Xaml code:
<Button Background="White"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="40" />
</Grid.ColumnDefinitions>
<!-- Content TextBlock -->
<TextBlock Text="{Binding MyVM.SelectedItem, Mode=TwoWay}"
Style="{StaticResource DefaultTextBlock}"
FontSize="22"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="10, 0, 0, 0"/>
<Image Height="20" Grid.Column="1"
VerticalAlignment="Center" HorizontalAlignment="Center"
Source="../Assets/icons/arrow_down.png"/>
</Grid>
<Button.Flyout>
<ListPickerFlyout PickerFlyoutBase.Title="$Items$"
ItemsSource="{Binding MyVM.listItems}"
SelectedItem="{Binding MyVM.SelectedItem, Mode=TwoWay}" >
<ListPickerFlyout.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding}"
Style="{StaticResource DefaultTextBlock}"
FontSize="22"/>
</StackPanel>
</DataTemplate>
</ListPickerFlyout.ItemTemplate>
</ListPickerFlyout>
</Button.Flyout>
And in MyVM i have
public string SelectedItem { get; set; }
Edit:
Solved the problem, i forgot to add RaisePropertyChanged("SelectedItem");.
So, in my MVVM class:
private string _selectedItem;
public string SelectedItem
{
get { return _selectedItem; }
set
{
if (_selectedItem != value)
{
_selectedItem = value;
RaisePropertyChanged("SelectedItem");
}
}
}
Just need to add the RaisePropertyChanged("SelectedItem"); in MVVM class.
The complete code:
private string _selectedItem;
public string SelectedItem
{
get { return _selectedItem; }
set
{
if (_selectedItem != value)
{
_selectedItem = value;
RaisePropertyChanged("SelectedItem");
}
}
}

How to Make Content Hidden in Expander Windows Phone Control

I am playing around with an example of Expander Control from Windows Phone Toolkit (I am using it for wp7).
When I load up the stripped down version everything seems expanded. When I click on Customer Pizza or 2 nothing happens. I would like the sub stuff to be collapsed but I don't know how.
<phone:PhoneApplicationPage
x:Class="ExpanderViewSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<phone:PhoneApplicationPage.Resources>
<toolkit:RelativeTimeConverter x:Key="RelativeTimeConverter"/>
<DataTemplate x:Key="CustomHeaderTemplate">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image}" Stretch="None"/>
<TextBlock Text="{Binding Name}"
FontSize="{StaticResource PhoneFontSizeExtraLarge}"
FontFamily="{StaticResource PhoneFontFamilySemiLight}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="CustomExpanderTemplate">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image}" Stretch="None"/>
<TextBlock Foreground="{StaticResource PhoneSubtleBrush}" VerticalAlignment="Center"
FontSize="{StaticResource PhoneFontSizeNormal}">
<TextBlock.Text>
<Binding Path="DateAdded" Converter="{StaticResource RelativeTimeConverter}" StringFormat="Date added: {0}" />
</TextBlock.Text>
</TextBlock>
</StackPanel>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="WindowsPhoneGeek.com" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="ExpanderViewSample" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle2Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListBox Grid.Row="0" x:Name="listBox">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<toolkit:ExpanderView Header="{Binding}" Expander="{Binding}"
IsExpanded="False"
HeaderTemplate="{StaticResource CustomHeaderTemplate}"
ExpanderTemplate="{StaticResource CustomExpanderTemplate}"></toolkit:ExpanderView>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
List<CustomPizza> customPizzas = new List<CustomPizza>()
{
new CustomPizza()
{
Name = "Custom Pizza 1",
IsExpanded = false,
DateAdded = new DateTime(2010, 7, 8),
Image="Images/pizza1.png"
},
new CustomPizza() { Name = "Custom Pizza 2", DateAdded = new DateTime(2011, 2, 10), Image="Images/pizza2.png"}
};
this.listBox.ItemsSource = customPizzas;
// Important properties:
// IsExpanded
// Header
// Expander
// ItemsSource
// HeaderTemplate
// ExpanderTemplate
// ItemTemplate
// NonExpandableHeader
// IsNonExpandable
// NonExpandableHeaderTemplate
}
}
public class CustomPizza : INotifyPropertyChanged
{
private bool isExpanded;
public string Image
{
get;
set;
}
public string Name
{
get;
set;
}
public DateTime DateAdded
{
get;
set;
}
public bool IsExpanded
{
get
{
return this.isExpanded;
}
set
{
if (this.isExpanded != value)
{
this.isExpanded = value;
this.OnPropertyChanged("IsExpanded");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
I also don't get what this really is for
ExpanderView Header="{Binding}" Expander="{Binding}"
I don't get what "binding" is referring too. It just seems to know which data to use but I don't know how it knows.
To change the expanded state of the expander view you can do the following
-register for tap event and add binding to IsExpanded (this will bind to the IsExpanded property of CustomPizza)
<toolkit:ExpanderView Header="{Binding}" Expander="{Binding}"
IsExpanded="{Binding IsExpanded}"
HeaderTemplate="{StaticResource CustomHeaderTemplate}"
ExpanderTemplate="{StaticResource CustomExpanderTemplate}"
Tap="expander_OnTap"></toolkit:ExpanderView>
-in the tap event switch the IsExpanded flag of the CustomPizza:
private void expander_OnTap(object sender, System.Windows.Input.GestureEventArgs e)
{
ExpanderView expander = sender as ExpanderView;
CustomPizza customPizza = expander.DataContext as CustomPizza;
customPizza.IsExpanded = !customPizza.IsExpanded;
}
Regarding the question about ExpanderView Header="{Binding}" Expander="{Binding}", when you set (or bind) the ItemsSource property of an ItemsControl to a list (ListBox is inheriting from a ItemsControl), the DataTemplate inside the ItemTemplate will be automatically set to each individual item. For example here you are setting it to a List of CustomPizza so each ItemTemplate DataContext will be a CustomPiza. So the ExpanderView will have the CustomPizza as DataContext. {Binding} will just pass the DataContext so like this whatever is inside the HEaderTemplate will get the same DataContext (CustomPizza ). If you had put {Binding Image} then the HeaderTemplate will just have the Image string as DataContext.

No data with ListBox with Grid inside

I am doing a Grid of two columns that are inside a ListBox. That after that I can DataBind the two columns to be repeated vertically.
So far the code below shows nothing on the WP7 emulator.
<ListBox Background="Yellow" ItemsSource="{Binding}" Height="100" Margin="0,0,8,0">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Height="100">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<TextBlock Text="Channels" HorizontalAlignment="Stretch" Foreground="Black" Grid.Column="0" />
<TextBlock Text="Antenna" HorizontalAlignment="Stretch" Foreground="Black" Grid.Column="1"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Please help me.
If your only concern is that you see ItemTemplate in action, you can supply explicit non-UI items as follows:
<ListBox Background="Yellow" Height="100" Margin="0,0,8,0" xmlns:sys="clr-namespace:System;assembly=mscorlib">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Height="30">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<TextBlock Text="Channels" HorizontalAlignment="Stretch" Foreground="Black" Grid.Column="0" />
<TextBlock Text="Antenna" HorizontalAlignment="Stretch" Foreground="Black" Grid.Column="1"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<sys:String>1111111</sys:String>
<sys:String>2222222</sys:String>
<sys:String>3333333</sys:String>
</ListBox>
Notes:
I removed ItemsSource and supplied items explicitly.
Items must not derive from UIElement so that they are templated. (UIElements are simply drawn and the template is ignored.)
I added System namespace so that string objects can be specified.
I decreased ItemTemplate height so that more than one list row is visible.
Easier solution:
Give the ListBox a name and remove the binding:
<ListBox x:Name="myLB" Background="Yellow" Height="100" Margin="0,0,8,0">
Then use this line in the code (after the call InitializeComponent()):
myLB.ItemsSource = new List<string> { "First", "Second", "Third" };
If you want design-time itemssource, you can use the IsInDesignMode property like so:
if (System.ComponentModel.DesignerProperties.IsInDesignTool)
{
myListBox.ItemsSource = GenerateMockItems();
}
else
{
myListBox.ItemsSource = GetRealItems();
}
in MVVMLight ViewModels, this is shortcut-ed as
if (IsInDesignMode)
{
}
Similarly, since it looks like you're setting your ItemsSource in xaml, inside your class that is your DataContext, you could do something like
public class MyViewModel
{
public MyViewModel()
{
if (System.ComponentModel.DesignerProperties.IsInDesignTool)
{
Items = GenerateMockItems();
EditTime = GenerateRandomFutureDate();
}
else
{
//whatever you expect should happen in runtime
}
}
//what list is binding to
public ObservableCollection<Item> Items { get; set; }
//other properties.. for example
public bool HasItems { get { return Items != null && Items.Count > 0; } }
public DateTime EditDate { get; set; }
private ObservableCollection<Item> GenerateMockItems()
{
var collection = new ObservableCollection<Item>();
for (int i = 0; i < 10; i++)
{
collection.Add(new Item() { Name="sdfsdfs" , Channel=i });
}
return collection;
}
private DateTime GenerateRandomFutureDate()
{
return DateTime.Now.AddSeconds(new Random().Next(0,50000));
}
}