ListPicker selected item not changing when selected in Full Mode - xaml

I have List of Categories that I want to display in a ListPicker. The Class is:
public class Category : INotifyPropertyChanged, INotifyPropertyChanging
{
private int _id;
public int Id
{
get { return _id; }
set
{
if (_id == value) return;
NotifyPropertyChanging();
_id = value;
NotifyPropertyChanged();
}
}
private string _description;
public string Description
{
get { return _description; }
set
{
if (_description == value) return;
NotifyPropertyChanging();
_description = value;
NotifyPropertyChanged();
}
}
#region INotifyPropertyChanging and INotifyPropertyChanged Members
public event PropertyChangingEventHandler PropertyChanging;
/// <summary>
/// Used to notify the data context that a property is about to change...
/// </summary>
private void NotifyPropertyChanging([CallerMemberName] string propertyName = null)
{
if (PropertyChanging != null) PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Used to notify the data context that a property has changed...
/// </summary>
private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
I have a ListPicker Full Mode Item Template defined as a XAML Resource:
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="FullModeItemTemplate">
<TextBlock d:DataContext="{Binding}"
Text="{Binding Description}"
/>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
and a Listpicker for it defined in XAML on the Page:
<phone:PhoneApplicationPage
x:Class="QuestionPage"
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"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeMedium}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot is the root grid where all page content is placed.-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Border Style="{StaticResource ButtonBorderStyle}"
Background="Blue"
BorderBrush="White"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the app and page title.-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="0,10,0,0">
<TextBlock x:Name="ApplicationTitle"
Text="pagetitle"
Style="{StaticResource PhoneTextLargeStyle}"/>
<TextBlock x:Name="PageTitle"
Text="subtitle"
Style="{StaticResource PhoneTextExtraLargeStyle}"/>
</StackPanel>
<StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="0,0,0,15">
<TextBlock Text="question" Margin="20,5,0,0"/>
<TextBox x:Name="ItemDescription"/>
<TextBlock Text="category" Margin="20,0,0,-10"/>
<toolkit:ListPicker x:Name="CategoriesListPicker"
DataContext="{Binding}" ItemsSource="{Binding Categories}"
DisplayMemberPath="Description"
FullModeHeader="Categories:"
FullModeItemTemplate="{StaticResource FullModeItemTemplate}"
CacheMode="BitmapCache"
>
</toolkit:ListPicker>
</StackPanel>
</Grid>
</Border>
</Grid>
</phone:PhoneApplicationPage>
The ItemDescription and Category are to be saved to a Question Class Item in another list... but this is not relevant to the problem...
If the Category List has five or less items in it, the selection list is displayed in short mode and items from the list can be selected and this selection is reflected in the control field. This is fine.
If I increase the Categories List to over five items, the ListPicker switches to full mode, and although the display of these is fine, when an item from the list is selected, the item shown in the control field remains unchanged.
Is this a bug in the Full Mode selection list or am I missing something?
Any help you can give will be appreciated...

In my original question I stated:
"The ItemDescription and Category are to be saved to a Question Class Item in another list... but this is not relevant to the problem..."
Although this is correct, it made me realise I'd not taken into consideration how the data items for the page containing the ListPicker are populated before it is displayed. This data population also includes setting the SelectedItem parameter for the ListPicker to the Category for the Question.
I set this data population to happen during the OnNavigatedTo protected override for the page. I'd not realised that the OnNavigatedTo method also gets triggered on return from the Full Mode Listpicker which of course then reset the SelectedItem to the original value for the Question. To avoid this problem, I put in a check for null on the QuestionId so OnNavigatedTo only populates the data items on initial entry to the page... problem solved!

Related

TreeViewItem template click/select/highlight issue

I am new to WinUI 3 and I am currently building a TreeView (CommunityToolkit) where I can drag/drop TreeViewItems on top of each other. The TreeViewItem that I have consist of 3 parts, a group name, a display name and children items. The drag/drop part of the code works fine, however there is an issue whereby clicking on an item doesn’t always select/highlight it and I cannot seem to find the root issue as to why. See image below.
In the image above, the first item is "selected" as I would like it to be with the blue highlight to the left. But when I click on either of the other 2 items (Level 1 or Level 2), I have observed the following behaviours.
A click on "U" or "Level 1" does not select the item. There is some "pressed" style showing, but once the mouse button is released nothing happens. There is no highlight or selected style present
A click just above or below the red line selects the item as I expect it to.
See the XAML below
<Grid>
<Border BorderThickness="2" BorderBrush="DimGray">
<TreeView AllowDrop = "True"
CanDragItems="True"
CanReorderItems = "False"
ItemsSource="{x:Bind Items}"
SelectedItem="{x:Bind SelectedDemoItem, Mode=TwoWay}">
<TreeView.ItemTemplate>
<DataTemplate x:DataType="local:DemoItem">
<TreeViewItem AllowDrop="True"
CanDrag="True"
CollapsedGlyph=""
ExpandedGlyph=""
IsExpanded="True"
ItemsSource="{x:Bind Children}"
Padding="-10,0,0,0">
<TreeViewItem.Content>
<StackPanel AllowDrop="True"
BorderBrush="Red"
BorderThickness="1"
CanDrag="True"
Orientation="Horizontal">
<TextBlock FontSize="14"
FontWeight="ExtraBold"
IsColorFontEnabled="True"
Margin="0,0,10,0"
MinWidth="30"
TextAlignment="Center"
Text="{x:Bind Group}" />
<TextBlock Text="{x:Bind DisplayName}" Margin="0,0,5,0"/>
</StackPanel>
</TreeViewItem.Content>
</TreeViewItem>
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Border>
</Grid>
And the code-behind
public sealed partial class TestUserControl : UserControl
{
public TestUserControl()
{
InitializeComponent();
FillData();
}
private void FillData()
{
var level0 = new DemoItem { DisplayName = "Level 0", Group = Groups.M };
var level1 = new DemoItem { DisplayName = "Level 1", Group = Groups.U };
var level2 = new DemoItem { DisplayName = "Level 2", Group = Groups.C };
level1.Children.Add(level2);
level0.Children.Add(level1);
Items.Add(level0);
Items.Add(level0);
}
public ObservableCollection<DemoItem> Items { get; } = new();
public DemoItem SelectedDemoItem { get; set; }
}
public enum Groups
{
S, M, U, C
}
public class DemoItem
{
public string DisplayName { get; set; }
public ObservableCollection<DemoItem> Children { get; } = new();
public Groups Group { get; set; }
}
For the purpose of this test, I have removed all drag/drop code as they have no affect on the problem above. However, it may help to mention that I have seen this problem occur only when CanDrag is set to True within my item template.
Any help to fix this will be greatly appreciated.
Click events won't reach the TreeViewItem because of the TextBlocks. The easiest way is to disable IsHistTestVisible on both TextBlocks.
<TextBlock
MinWidth="30"
Margin="0,0,10,0"
FontSize="14"
FontWeight="ExtraBold"
IsColorFontEnabled="True"
IsHitTestVisible="False"
Text="{x:Bind Group}"
TextAlignment="Center" />
<TextBlock
Margin="0,0,5,0"
IsHitTestVisible="False"
Text="{x:Bind DisplayName}" />

Expander Control - UWP

I have an expander control in my UWP app with the following code:
<Expander
Header="A"
IsExpanded =" True">
<TextBlock
Text="Content in A"/>
</Expander>
<Expander
Header="B">
<TextBlock
Text="Content in B"/>
</Expander>
Currently expander A is expanded by default and B is closed. However, when I expand B, A is also open. I would like the behavior that if I expand one , the other closes and vice versa. Any suggestions as to how I can achieve this in an MVVM way ? Would i need to use converters here? I looked into Collapse all the expanders and expand one of them by default but most of the solutions happen to be in modifying the code behind. How do i achieve the same if i have a XAML code in Main.xaml and i have a corresponding MainPageViewModel.cs?
I would like the behavior that if I expand one , the other closes and vice versa.
For this scenario, you could use OppositConverter to make the other expender close when previous is open.
public class OppositConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return !(bool)value;
}
}
public class MainPageViewModel : INotifyPropertyChanged
{
public MainPageViewModel()
{
}
private bool _isExpend;
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string name = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public bool IsExpend
{
get
{
return _isExpend;
}
set
{
_isExpend = value;
OnPropertyChanged();
}
}
}
Usage
<Page.DataContext>
<local:MainPageViewModel x:Name="ViewModel" />
</Page.DataContext>
<Page.Resources>
<local:OppositConverter x:Key="OppositConverter" />
</Page.Resources>
<StackPanel>
<controls:Expander
x:Name="Expander1"
Margin="0,0,0,10"
VerticalAlignment="Top"
HorizontalContentAlignment="Stretch"
ExpandDirection="Down"
Header="This is the header - expander 1"
IsExpanded="{Binding IsExpend, Mode=TwoWay}">
<Grid>
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="This is the expanded content"
TextWrapping="Wrap" />
</Grid>
</controls:Expander>
<controls:Expander
x:Name="Expander2"
Margin="0,0,0,10"
VerticalAlignment="Top"
HorizontalContentAlignment="Stretch"
ExpandDirection="Down"
Header="This is the header - expander 2"
IsExpanded="{Binding IsExpend, Converter={StaticResource OppositConverter}, Mode=TwoWay}">
<Grid>
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="This is the expanded content"
TextWrapping="Wrap" />
</Grid>
</controls:Expander>
</StackPanel>

Update UserControl Textblock text from mainpage.xaml

I am writing a Windows Phone 8.1 Silverlight App. I made a user control NotificationsIconUserControl. It just contains a BELL/ALARM icon and textblock to display number of unread notifications.
I want to update this textblock text from mainpage.xaml
How to do this?
I tried using usercontrol expose properties but its the opposite thing. Also tried help from this question. how to use dependency property. Please edit the code below:
Usercontrol XAML:
<Grid x:Name="LayoutRoot"
Background="Transparent"
Height="Auto"
Width="Auto">
<Image
Name="Alarm_Icon"
Source="/Images/Status/Notification_Icon_1.png">
</Image>
<Ellipse
Name="Counter_Icon"
Height="45"
Width="45"
Margin="60,14,-6,50"
StrokeThickness="0"
Fill="{StaticResource DefaultTheme_IndianRedColor}">
</Ellipse>
<TextBlock
Name="Counter_Label"
Foreground="{StaticResource DefaultTheme_LightColor}"
FontSize="30"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextAlignment="Center"
Margin="75,20,8,58"/>
</Grid>
Mainpage XAML part:
xmlns:MyUserControls="clr-namespace:Project.Custom.UserControls">
Mainpage .cs part:
private void ConfigureNotificationsIcon()
{
int NotificationsCounter = 4;
NotificationsIconUserControl NotificationsIconUserControlObject = new NotificationsIconUserControl();
NotificationsIconUserControlObject.Counter_Label.Text = NotificationsCounter.ToString();
}
I checked your code and its working completely....
ANd for the part of adding a Dependency property, write the following in the .cs file of UserControl
public partial class NotificationIconUserControl : UserControl
{
public NotificationIconUserControl()
{
InitializeComponent();
}
public string NotificationLabel
{
get { return (string)GetValue(NotificationLabelProperty); }
set { SetValue(NotificationLabelProperty, value); }
}
// Using a DependencyProperty as the backing store for Spacing. This enables animation, styling, binding, etc...
public static readonly DependencyProperty NotificationLabelProperty =
DependencyProperty.Register("NotificationLabel", typeof(string), typeof(NotificationIconUserControl), new PropertyMetadata("hellllo"));
}
After that you can use TemplateBinding to do your job

Why LonglistSelector not display items though it display GroupHeaderItem?

My LonglistSelector only displays GroupHeaderTemplate Data (ImageSource,Title) but ItemTemplate DataTemplate (SubItemTitle, Location) not displayed. How can i solve it?
public class Data
{
public string Title { get; set; }
public string ImageSource { get; set; }
public List<SubItem> SubItems { get; set; }
public Data()
{
SubItems = new List<SubItem>();
}
}
public class SubItem
{
public string SubItemTitle { get; set; }
public string Location { get; set; }
}
<phone:LongListSelector ItemsSource="{Binding DataCollection}" Grid.Row="0" IsGroupingEnabled="True">
<phone:LongListSelector.GroupHeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="10">
<Image Source="{Binding ImageSource}"/>
<TextBlock Text="{Binding Title}"/>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.GroupHeaderTemplate>
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding SubItemTitle}" Padding="5" FontSize="40"/>
<TextBlock Text="{Binding Location}" Padding="5" FontSize="40"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
You have to convert whatever the class you are using to group the items from inheriting. Try using the List than the IEnumerator.
This one discusses the same longlistselector issue.
Grouped LongListSelector: headers appear, items don't
Hope it helps!
This MSDN example helped me a lot when I had trouble understanding Grouping with LongListSelector
How to display data in a grouped list in LongListSelector for Windows Phone 8
It needs to be Grouped by a Key Value. Of all the of the examples I know of it's always something like this:
List<AlphaKeyGroup<your_data_type>> my_group_list; // or
ObservableCollection<AlphaKeyGroup<your_data_type>> my_group_list;
Not a List that has a property that is a SubList.
AlphaKeyGroup is just a List<T>/ObservableCollection<T> with an extra property for a Key
Think of it this way, in your code how does the LongListSelector know that your "Title" is the group key rather than the "ImageSource"?
If the code on the MSDN page is too complicated to understand, you can always take the easier route and use LINQ using the GroupBy.
Here a SO example: Group by in LINQ

Two UserControls, one binds, one doesn't

I have two very simple UserControls in a simple WinRT demo project. No Viewmodel--mostly just colored boxes for layout exploration. The first UserControl I created works fine. The second, very similar one, won't bind to any properties--it shows up as blank.
The first UserControl looks like this:
<UserControl
x:Class="Demo.SmallStartTile"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Demo"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Name="SmallStartTileUC"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid x:Name="SmallTileGrid"
Margin="0,0,8,8"
Background="{Binding Background, ElementName=SmallStartTileUC}"
>
<Rectangle
Stroke="{Binding BorderBrush, ElementName=SmallStartTileUC}"
Grid.RowSpan="2"
/>
<TextBlock x:Name="SmallTileTitle"
Text="{Binding TileText, ElementName=SmallStartTileUC}"
Style="{StaticResource SmallTileHeader}"/>
<Path x:Name="IconPath"
Style="{StaticResource SmallTileIcon}"
Data="{Binding TileIconPathData, ElementName=SmallStartTileUC}" />
</Grid>
</UserControl>
namespace Demo
{
public sealed partial class SmallStartTile : UserControl
{
public static DependencyProperty TileTextProperty = DependencyProperty.Register("TileText", typeof(string), typeof(SmallStartTile), new PropertyMetadata("tile content"));
public string TileText
{
get { return (string)GetValue(TileTextProperty); }
set { SetValue(TileTextProperty, value); }
}
public static DependencyProperty TileIconPathDataProperty = DependencyProperty.Register("TileIconPathData", typeof(string), typeof(SmallStartTile), new PropertyMetadata("F0"));
public string TileIconPathData
{
get { return (string)GetValue(TileIconPathDataProperty); }
set { SetValue(TileIconPathDataProperty, value); }
}
public SmallStartTile()
{
this.InitializeComponent();
}
}
}
And the second one, which I made just like the first one by clicking Add New Item and picking UserControl in Blend:
<UserControl
x:Class="Demo.SmallMediaTile"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Demo"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Name="SmallMediaTileUC"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid
Margin="0,0,8,8"
Background="{Binding Background, ElementName=SmallMediaTileUC}"
>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Rectangle
Stroke="{Binding BorderBrush, ElementName=SmallMediaTileUC}"
Grid.RowSpan="2"
/>
<Viewbox
Margin="30"
Child="{Binding Content, ElementName=SmallMediaTileUC}">
</Viewbox>
<TextBlock
Grid.Row="1"
Text="{Binding SourceText, ElementName=SmallMediaTileUC}"
Style="{StaticResource SmallMusicTileHeader}"/>
</Grid>
</UserControl>
namespace Demo
{
public sealed partial class SmallMediaTile : UserControl
{
public static DependencyProperty SourceTextProperty = DependencyProperty.Register("SourceText", typeof(string), typeof(SmallMediaTile), new PropertyMetadata("source"));
public string SourceText
{
get { return (string)GetValue(SourceTextProperty); }
set { SetValue(SourceTextProperty, value); }
}
public SmallMediaTile()
{
this.InitializeComponent();
}
}
}
I use the UserControl in the main Page like this:
<local:SmallMediaTile x:Name="Source1Tile"
Grid.Column="0" Grid.Row="0"
SourceText="Radio"
Background="Blue"
BorderBrush="Red">
<local:SmallMediaTile.Content>
<Canvas x:Name="radio_icon" Height="68" Width="34">
<Path Data="F1M299.6182,396.2988C299.6182,389.7208,297.0722,383.5548,292.4572,378.8398L288.6162,382.6758C292.2022,386.3718,294.1842,391.1778,294.1842,396.2988C294.1842,401.4238,292.2022,406.2368,288.6162,409.9328L292.4572,413.7738C297.0722,409.0538,299.6182,402.8808,299.6182,396.2988" Fill="White" Height="34.934" Canvas.Left="0" Stretch="Fill" Canvas.Top="16.501" Width="11.002"/>
<Path Data="F1M311.1738,396.2988C311.1738,386.6278,307.4348,377.5528,300.6788,370.6208L296.8258,374.4618C302.5658,380.3698,305.7398,388.0798,305.7398,396.2988C305.7398,404.5218,302.5658,412.2298,296.8258,418.1428L300.6788,421.9898C307.4348,415.0498,311.1738,405.9718,311.1738,396.2988" Fill="White" Height="51.369" Canvas.Left="8.21" Stretch="Fill" Canvas.Top="8.282" Width="14.348"/>
<Path Data="F1M322.7578,396.2988C322.7578,383.5298,317.8508,371.5348,308.9638,362.3388L305.1168,366.1748C312.9758,374.3538,317.3338,384.9778,317.3338,396.2988C317.3338,407.6208,312.9758,418.2488,305.1168,426.4268L308.9638,430.2748C317.8508,421.0698,322.7578,409.0798,322.7578,396.2988" Fill="White" Height="67.936" Canvas.Left="16.501" Stretch="Fill" Canvas.Top="0" Width="17.641"/>
</Canvas>
</local:SmallMediaTile.Content>
</local:SmallMediaTile>
The first one picks up all the properties and displays like I expect, but the second one only picks up the Viewbox content. I've looked through SO and been googling but can't figure out what the problem is. Sorry if this is longwinded.
Your root Grid is set as the Content of the UserControl while the Viewbox you have is trying to bind its Child property to the Content of the UserControl that is its ascendant. That is not allowed since the root Grid is already a parent of the UserControl and XAML controls can only exist in one place in the UI.
As noted, the problem is the UserControl's content can only be set once. When I bind the Viewbox Content to the UserControl content, the existing XAML is replaced. So, a blank box but for what I'm passing in. I guess to do what I had hoped, I'd need to make a custom control. Thanks for the help!