FlipView creating additional FlipViewItem on resize - xaml

I have a FlipView with items and and an item template. Initially when the control is loaded, three FlipView items are created. I noticed that if I resize the window after that, the FlipView decides to create an additional fourth item. To demonstrate this strange behaviour I've created the following small example:
<Page
x:Class="Test.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Test"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<FlipView x:Name="items">
<FlipView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Loaded="TextBlock_Loaded"/>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
</Grid>
And this is the code-behind:
public sealed partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
items.ItemsSource = new string[] { "Text 1", "Text 2", "Text 3", "Text 4" };
}
private void TextBlock_Loaded(object sender, RoutedEventArgs e)
{
var textBlock = sender as TextBlock;
System.Diagnostics.Debug.WriteLine(textBlock.Text);
}
}
When the page is loaded, you will see "Text 1", "Text 2", "Text 3" in the program output. Then if you try to resize the window while still on the first item, "Text 4" will also appear in the output.
My question is: Why does this happen and can I do anything to prevent it?

When the page is loaded, you will see "Text 1", "Text 2", "Text 3" in the program output. Then if you try to resize the window while still on the first item, "Text 4" will also appear in the output.
The root cause of this behavior: FlipView is using VirtualizingStackPanel as its itemsPanel. When you have a lot of items VirtualizingStackPanel will load the items as needed, which will increase the performance.
To prevent it, you only need to replace the itemsPanel with other "not Virtualized Panel":
<FlipView x:Name="items" Style="{StaticResource FlipViewStyle1}">
<FlipView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</FlipView.ItemsPanel>
<FlipView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Loaded="TextBlock_Loaded"/>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
Notes:Please note that disabling UI virtualization for FlipView may negatively impact performance especially when there are a lot of big size items.

Related

Button to change background colour

I'm developing a UWP app. I would like to have a radio button change the background of the mainpage and settings page when clicked. The radio button code below is in Settings.xaml.cs
private void BGRadioButtonGreen_Checked(object sender, RoutedEventArgs e)
{
MainPage.Background = Brushes.Red??;
}
In this example I'm trying to select a radio button and have it change the settings and mainpage background to Green.However it doesn't seem to be working. Thanks in advance
You can do it be setting background color of root grid. Like in example below, after radio button checked color would change to red. This should be what you're looking for.
<Page
x:Class="Test.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Test"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Background="Blue">
<Grid x:Name="MainGrid" Background="Green">
<StackPanel>
<RadioButton Content="Red" Tag="Green" Checked="RadioButton_Checked"/>
</StackPanel>
</Grid>
private void RadioButton_Checked(object sender, RoutedEventArgs e)
{
MainGrid.Background = new SolidColorBrush(Windows.UI.Colors.Red);
}
For changing background color, as #ColdMorningLight mentioned, you should set a SolidColorBrush value to the Background property.
Since you attempt to change the MainPage background color from Settings page, which is in different pages, you also need to get the current MainPage instance firstly and then set the page's background. For example:
MainPage mainPage;
public SettingPage()
{
this.InitializeComponent();
mainPage = (Window.Current.Content as Frame).Content as MainPage;
}
private void radchangecolor_Checked(object sender, RoutedEventArgs e)
{
mainPage.Background = new SolidColorBrush(Windows.UI.Colors.Green);
}
Pay attention that I set the page's background color, you only can see the effects when the root panel background color is transparent (the default value is Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" ). Otherwise you need to change the root panel background color. For example, MainPage as follows will take effects:
<Page
...
mc:Ignorable="d" >
<StackPanel>
<Frame x:Name="frame" Height="200" Width="300" Background="Azure"></Frame>
<Button x:Name="btntest" Click="btntest_Click" Content="test"></Button>
</StackPanel>
</Page>

Create a component and reuse it in Windows phone 8.1

I want to create some components and reuse them in different pages, put more than one in a page, etc.
For example, I want to create a component that contains an image, some text, etc. The position of the elements are fixed, but I will change the image, the text... I mean, in a same page I want to put three circles with different image and text...
What is the best way to do it? I've found UserControl, but I'm unable to call a method from another page to change something.
This is my component XAML
<UserControl
x:Class="aa.Components.CircularGraph"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Components"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="300">
<Grid Name="view">
<Image Name="imageGraph" Source="../Assets/aa/circuloGris.png"
/>
<StackPanel Orientation="Vertical">
<TextBlock Name="firstLine" Text="1" FontFamily="Arial" FontSize="9"></TextBlock>
<TextBlock Name="secondLine" Text="2" FontFamily="Arial" FontSize="9"></TextBlock>
<TextBlock Name="thirdLine" Text="3" FontFamily="Arial" FontSize="9"></TextBlock>
</StackPanel>
</Grid>
</UserControl>
Its code:
public sealed partial class CircularGraph: UserControl {
public CircularGraph() {
this.InitializeComponent();
Height = 300;
Width = 400;
}
public void changeFirstLine(string var) {
firstLine.Text = var;
}
}
In other page I put:
<local:CircularGraph Name="circularGraph"/>
And I've tried to put this in .cs:
protected override void OnNavigatedTo(NavigationEventArgs e) {
circularGraph.changeFirstLine("aaa");
}
But I have an error: The name 'circularGraph' does not exits in the current context.
How can I do this?
Sorry if it's a simple question. I'm newbie at Windows phone.
Thank you very much!
Try x:Name instead of Name. "All x:Name means to XAML is generate a field to store the value in the code behind class."
<local:CircularGraph x:Name="circularGraph"/>
In WPF, what are the differences between the x:Name and Name attributes?

ListPicker selected item not changing when selected in Full Mode

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!

Load a Page into a ContentControl

I have a ContentControl where I want to load the page myPage2. My XAML Codefrom this page looks like this:
<Page x:Class="ExampleApp.myPage2">
<Grid x:Name="Content" Height="651" Width="941" Background="White">
...
...
</Grid>
</Page>
I know that I can load a resource from a page with this Code:
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
var contentControl = (ContentControl)container;
return (DataTemplate) contentControl.Resources[templateKey];
}
My problem now is that I can't load a page like above with this code. I have to write this:
<Page x:Class="ExampleApp.myPage2">
<Page.Resources>
<DataTemplate x:Key="Test">
<Grid x:Name="Content" Height="651" Width="941" Background="White">
...
...
</Grid>
</DataTemplate>
</Page.Resources>
</Page>
And then I can load the page with the same Code from above with templateKey="Test". But the main problem is that I want to use the first declaration of the page and do not want to use <Page.Resources> <DataTemplate x:Key="Test"> and so on. I want to load the site direcly from the first declaration (first code in this post). How can I create a DataTemplate directly from a page? Or is there an other way to load a page into a ContentControl?
There is no reason to use a Page within a ContentControl. A Page is a subclass of the UserControl class that adds support for being used within a Frame control to support navigation, back stack/history, etc. You should probably replace Page with UserControl in XAML and code behind, so you would end up with something like this:
<UserControl x:Class="ExampleApp.myControl2">
<Grid x:Name="Content" Height="651" Width="941" Background="White">
...
...
</Grid>
</UserControl>
You can put the UserControl itself in a DataTemplate if you want to use it as a DataTemplate in a ContentControl:
<ContentControl
xmlns:controls="using:ExampleApp">
<ContentControl.Resources>
<DataTemplate
x:Key="Test">
<controls:myControl2 />
</DataTemplate>
</ContentControl.Resources>
</ContentControl>

XAML how to make a textblock/text box edit toggle?

I may be approaching this all wrong, so tell me if you have an alternative suggestions.
I'm making an app for windows RT that will have a bunch of text blocks displayed to the user, for example character stats.
The user will see:
Str: 10
Con: 10
Dex: 10
and so on.
I want them to be able to fill these in, then have a select view values calculated based on the result.
My though was to click an "Edit" button at the top and toggle some text boxes over each editable text block.
When trying to set this up using "Blend for Visual Studio" I can't seem to make a text box that is smaller than 49x34 (much larger than my text blocks).
I was going to find a way to generate a text box for each text block (using its dimensions) on button click, but since they will always be the same and there will be a lot of them I was trying to make them static via blend.
I'm pretty new to XAML, and I can't seem to find a good example of people setting up editable fields like this, so how should I make a bunch of static fields have editable text boxes?
I would create both the TextBox and TextBlock overlays in XAML, and place them directly on top of each other in a Grid, using Horizontal and Vertical alignments to "Center" to ensure that the text is always completely lined up. I would also use static Widths to ensure that the columns line up well.
From there, you can directly bind the Visibility to some boolean "IsEditing" property, to make sure that only one of the controls are shown at a time.
<StackPanel Orientation="Horizontal">
<TextBlock Text="Str: " Width="40" VerticalAlignment="Center" />
<Grid Width="40" VerticalAlignment="Center">
<TextBlock Text="{Binding Strength}"
Visibility="{Binding IsEditing, Converter={StaticResource BooleanToInvisibilityConverter}}"
VerticalAlignment="Center"
HorizontalAlignment="Center" />
<TextBox Text="{Binding Strength}"
Visibility="{Binding IsEditing, Converter={StaticResource BooleanToVisibilityConverter}}"
VerticalAlignment="Center"
HorizontalContentAlignment="Center" />
</Grid>
</StackPanel>
Somewhere along the way you'll have to define your "BooleanToVisibility" and "BooleanToInvisiblity" converter resources. I like this implementation by Diedrik Krols. It's nice and simple, with the option to invert.
You might want to use a style for a TextBox, which changes depending on whether or not the "IsReadOnly" property is true or not.
When IsReadOnly is true, you can set the BorderBrush and Background to Transparent, thus making it look like a normal textblock.
In this way, you don't have to overlay TextBlocks and TextBoxes; just use TextBox controls by themselves, and toggle the "IsReadOnly" property when you click the Edit button.
In your resources:
<Style x:Key="MyEditableField" TargetType={x:Type TextBox}>
<Style.Triggers>
<DataTrigger Binding="{Binding IsReadOnly, RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Background" Value="Transparent" />
</DataTrigger>
</Style.Triggers>
</Style>
And here's one of your editable fields:
<StackPanel Orientation="Horizontal">
<TextBlock Text="Str: " />
<TextBox Style="{StaticResource MyEditableField}"
Text="{Binding Strength}"
IsReadOnly="{Binding IsEditingDisabled}" />
</StackPanel>
Late answer, but who wants can also create a custom editable textbox, its pretty easy actually here is the code (obviously you can modify it for your own needs)
public class EditableTextBox : TextBox
{
public EditableTextBox()
{
this.BorderBrush = new SolidColorBrush(Colors.Black);
}
protected override void OnTapped(TappedRoutedEventArgs e)
{
this.IsReadOnly = false;
SetEditingStyle();
base.OnTapped(e);
}
protected override void OnDoubleTapped(DoubleTappedRoutedEventArgs e)
{
this.IsReadOnly = false;
SetEditingStyle();
base.OnDoubleTapped(e);
}
protected override void OnLostFocus(RoutedEventArgs e)
{
this.IsReadOnly = true;
SetReadonlyStyle();
base.OnLostFocus(e);
}
public void SetReadonlyStyle()
{
this.BorderBrush.Opacity = 0;
this.Background.Opacity = 0;
}
public void SetEditingStyle()
{
this.BorderBrush.Opacity = 1;
this.Background.Opacity = 1;
}
}
Sample:
Tutorial: Full tutorial url
Using a property to toggle edit mode between view AND viewmodel is a bad design approach you should use events and command binding to communicate changes of states like this between view and viewmodel.
Here is an article that describes the principle in an MVVM compliant way:
http://www.codeproject.com/Articles/802385/A-WPF-MVVM-In-Place-Edit-TextBox-Control
Please have a look and tell me what you think.
This builds off of BTownTKD's solution, but as I really do prefer as much WPF of a solution as possible here is a bit of a modification, in my case I'm trying to modify the name of a tab control.
My view model has the following code:
private bool _isEditingName = false;
public bool IsEditingName
{
get
{
return _isEditingName;
}
set
{
_isEditingName = value;
OnPropertyChanged();
}
}
public ICommand StartEditing
{
get
{
return new DelegateCommand(() =>
{
IsEditingName = true;
});
}
}
public ICommand EndEditing
{
get
{
return new DelegateCommand(() =>
{
IsEditingName = false;
});
}
}
Next is my view that has the data template for the tab (not the content just the tab):
<TabControl ItemsSource="{Binding Items}" SelectedItem="{Binding ActiveItem}">
<TabControl.ItemTemplate>
<DataTemplate>
<Grid VerticalAlignment="Center">
<TextBlock x:Name="TabName" Text="{Binding Name}" Visibility="{Binding IsEditingName, Converter={StaticResource InvertedBoolToVisConverter}}" VerticalAlignment="Center" HorizontalAlignment="Stretch" TextAlignment="Left">
<TextBlock.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick" Command="{Binding StartEditing}" />
</TextBlock.InputBindings>
</TextBlock>
<TextBox Text="{Binding Name}" Visibility="{Binding IsEditingName, Converter={StaticResource BoolToVisConverter}}" VerticalAlignment="Center" HorizontalContentAlignment="Stretch" TextAlignment="Left" IsVisibleChanged="TextBox_IsVisibleChanged">
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus">
<i:InvokeCommandAction Command="{Binding EndEditing}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding EndEditing}" />
</TextBox.InputBindings>
</TextBox>
</Grid>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
And last but not least, I wanted a double click to put me in edit mode, and to auto focus on the textbox and select all of the content for immediate typing. None of the xaml solutions were as clean as a simple code behind so I finally just decided on adding this to the textbox on visibility changed handler:
private void TextBox_IsVisibleChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e)
{
var box = sender as TextBox;
if (box != null)
{
if ((bool)e.NewValue)
{
box.Focus();
box.SelectAll();
}
}
}
Out of all of the solutions I found, this was by far my favorite. Thanks everyone for your posts!! Helped me find a really good overall solution to my problem!