Dynamically add tabs to tab control - xaml

I am trying to dynamically add tabs to tab control. I have control template in resources:
<ControlTemplate x:Key="memoTab" TargetType="{x:Type TabItem}">
<TabItem Header="Memo">
<TextBox Name="memoText"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
AcceptsReturn="True"/>
</TabItem>
</ControlTemplate>
I create tab in code behind:
TabItem tab = new TabItem();
tab.Template = (ControlTemplate) FindResource("memoTab");
tab.ApplyTemplate();
TextBox tb = (TextBox) tab.Template.FindName("memoText", tab);
tb.DataContext = memo; //this is a string created by linq query
tabControl.Items.Add(tab);
I end up with tab visible in tab control, but it is not selectable, and I cannot see anything in it.

I could reproduce it, try this way instead:
private void Button_Click(object sender, RoutedEventArgs e)
{
var content = new TextBlock();
content.Text = "Hello World! " + new Random().Next(1, 20).ToString();
TabItem tab = new TabItem();
tab.Header = "Hello world!";
tab.Content = content;
tabControl.Items.Add(tab);
}
UI
<Grid>
<TabControl Name="tabControl">
<TabItem Header="Existing tab 1" />
<TabItem Header="Existing tab 2" />
</TabControl>
<Button HorizontalAlignment="Left" VerticalAlignment="Bottom" Content="Add Tab" Width="100" Height="30" Click="Button_Click" />
</Grid>
Hope this helps!

Related

How to create an identical button to the one in 'Settings' page?

I want to create buttons on my UWP/XAML app similar to the buttons on the Windows 'Settings' page using the WinUI 3 library. The gallery didn't show this kind of button with an icon and a title/description. I'm wondering how it can be accomplished since I am developing an app that mostly serves as a portal to go to websites and navigate easily through web/PC apps. Any help would be appreciated.
I want the buttons to simply redirect the user to a NavigationView page (Page5.xaml)
I have a NavigationView on MainPage.xaml and these buttons are going on Page4, so I'm not sure how I can program the buttons to go to Page5.xaml
https://i.stack.imgur.com/7Uff8.png
You can create a usercontrol and use some of my code:
MyUserControl.xaml:
<Grid x:Name="MainGrid" PointerEntered="Grid_PointerEntered" PointerExited="Grid_PointerExited" PointerPressed="FontIcon_PointerPressed" Margin="20,5,20,5" Height="70" CornerRadius="5" Padding="{StaticResource ExpanderHeaderPadding}" HorizontalAlignment="Stretch" Background="{ThemeResource ExpanderHeaderBackground}" BorderThickness="{ThemeResource ExpanderHeaderBorderThickness}" BorderBrush="{ThemeResource ExpanderHeaderBorderBrush}">
<StackPanel Orientation="Horizontal" Margin="0,20,0,20">
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="" Margin="0,0,20,0"/>
<TextBlock FontSize="24" VerticalAlignment="Center" HorizontalAlignment="Left" Text="Font"/>
</StackPanel>
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="" HorizontalAlignment="Right" Margin="0,0,20,0"/>
</Grid>
MyUserControl1.xaml.cs:
public MyUserControl1()
{
this.InitializeComponent();
var color = (MainGrid.Background as SolidColorBrush).Color;
color.A = 20;
MainGrid.Background = new SolidColorBrush(color);
}
private void FontIcon_PointerPressed(object sender, PointerRoutedEventArgs e)
{
if (e.GetCurrentPoint(sender as UIElement).Properties.IsLeftButtonPressed)
{
//Do whatever you want
Debug.WriteLine("Pressed");
}
}
//Change the color on hover:
private void Grid_PointerEntered(object sender, PointerRoutedEventArgs e)
{
var color = (MainGrid.Background as SolidColorBrush).Color;
color.A = 50;
MainGrid.Background = new SolidColorBrush(color);
}
private void Grid_PointerExited(object sender, PointerRoutedEventArgs e)
{
var color = (MainGrid.Background as SolidColorBrush).Color;
color.A = 20;
MainGrid.Background = new SolidColorBrush(color);
}

Windows UWP ScrollViewer scrollbar overlaps contents

How do you stop a ScrollViewer's scrollbar from overlapping content like this?
I have a RichTextBlock containing text and no matter how wide I make the RichTextBlock, or how I change the Margin and Padding values, I cannot get the scrollbar to move further to the right to stop this overlap from happening. I'm running Windows 10 and it is configured to hide scrollbars until the mouse pointer hovers over them.
Below is the XAML for my app.
<Page
x:Class="PaulWinPOS1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:PaulWinPOS1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid Margin="0,26,0,0">
<Button x:Name="butConnect" Content="Connect" Margin="0,38,48,0" VerticalAlignment="Top" RenderTransformOrigin="-3.274,0.344" HorizontalAlignment="Right" Height="32" Click="ButConnect_Click" Width="92"/>
<Button x:Name="butLogin" Content="Login" Margin="0,92,48,0" VerticalAlignment="Top" RenderTransformOrigin="-3.274,0.344" HorizontalAlignment="Right" Height="32" Width="92" IsEnabled="False" Click="ButLogin_Click"/>
<Button x:Name="butAdd" Content="Add Item" Margin="0,143,48,0" VerticalAlignment="Top" RenderTransformOrigin="-3.274,0.344" HorizontalAlignment="Right" Width="92" IsEnabled="False" Click="ButAdd_Click"/>
<ScrollViewer x:Name="scrollViewerWeb"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
HorizontalAlignment="Left"
Width="350"
Padding="16,0"
Grid.RowSpan="10"
FontFamily="Segoe UI" RequestedTheme="Dark" ZoomMode="Enabled"
Margin="669,304,0,0" >
<WebView x:Name="webviewReceipt"
Margin="10,10,50,10"
HorizontalAlignment="Left"
Height="333" Width="300"
VerticalAlignment="Top"
ScrollViewer.VerticalScrollMode="Enabled"
ScrollViewer.VerticalScrollBarVisibility="Visible" />
</ScrollViewer>
<Button x:Name="butDisconnect" Content="Disconnect" Margin="0,244,48,0" VerticalAlignment="Top" RenderTransformOrigin="-3.274,0.344" HorizontalAlignment="Right" Height="32" Width="92" Click="ButDisconnect_Click"/>
</Grid>
</Page>
The scroll bar of WebView is special and cannot be solved by the conventional ScrollViewer additional properties, but the scroll bar of the WebView can be disabled through the CSS of the web page.
body {
-ms-overflow-style: none;
}
If you cannot modify the source code of the webpage, you can perform the following operations after the WebView content is loaded:
private async void webviewReceipt_DOMContentLoaded(WebView sender, WebViewDOMContentLoadedEventArgs args)
{
string js = "var style = document.createElement('style');" +
"style.type = 'text/css';" +
"style.innerHTML = \"body{ -ms-overflow-style: none !important; }\";" +
"document.getElementsByTagName('Head').item(0).appendChild(style); ";
await webviewReceipt.InvokeScriptAsync("eval", new string[] { js });
}
Update
If we need to display a scroll bar, we can add a padding-right to the body so that the scroll bar does not block the content.
private async void webviewReceipt_DOMContentLoaded(WebView sender, WebViewDOMContentLoadedEventArgs args)
{
string js = "var style = document.createElement('style');" +
"style.type = 'text/css';" +
"style.innerHTML = \"body{ padding-right: 24px; }\";" +
"document.getElementsByTagName('Head').item(0).appendChild(style); ";
await webviewReceipt.InvokeScriptAsync("eval", new string[] { js });
}
You need to add a Padding to ScrollViewer.
<ScrollViewer Padding="18, 0">
<RichTextBlock />
</ScrollViewer>
Usually the ScrollBar Width is 18.
It looks like you have the scroll bars enabled on both the web view and scroll viewer. You can try disabling the scroll bars on one of them to see if it makes a difference.

Long list selector windows phone child control event in DataTemplate

I am searching for this long time and i couldn't get it.
I have a Long list selector in my windows phone 8 project.
How can i manage the button event in each item in the data template? I need to get the selected item in that button event.
Code snippet shown below. Please help.
try this
// in your button click event type this code
var selectedValue = ((sender as Button).dataTemplate;
or
var selectedValue = ((sender as Button).dataTemplate as SbCaDd).AcNo;
If you want to access the dataContext then try this one.
XAML
<phone:LongListSelector Grid.Row="1"
Name="llsMsg"
LayoutMode="List"
VirtualizingStackPanel.VirtualizationMode="Recycling">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel>
<Grid>
<TextBlock Text="{Binding}"
Foreground="Black" />
<Button Content="View Details"
Width="200"
Click="Button_Click"/>
</Grid>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
C#
private void Button_Click(object sender, RoutedEventArgs e)
{
var dataContext = (sender as Button).DataContext;
var dataContext = (sender as Button).DataContext as YourDataModel;
}

Displaying a Progress Bar

I have an image control in my main page and the code is as follows:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel HorizontalAlignment="Left" Height="597" VerticalAlignment="Top" Width="440">
<Image x:Name="hinh1" Height="488" Stretch="Fill"/>
<ProgressBar Name="loading" Height="10" IsIndeterminate="True" Visibility="Collapsed"/>
</StackPanel>
</Grid>
and in code behind i have this code :
Uri hinh = new Uri
("http://taigamejar.net/wp-content/uploads/2014/01/Hinh-Anh-Dep-5.jpg", UriKind.Absolute);
hinh1.Source = new BitmapImage(hinh);
While waiting for the image to load, I want to call progress bar run to inform the user that it is loading. Once the the image has loaded, the progress bar should disappear. How can I do this?
If I were you, I would prefer to use , not ProgressBar.
So, I'll give
protected override void OnNavigatedTo(NavigationEventArgs e)
{
loading.IsActive = true;
Uri hinh = new Uri
("http://taigamejar.net/wp-content/uploads/2014/01/Hinh-Anh-Dep-5.jpg", UriKind.Absolute);
hinh1.Source = new BitmapImage(hinh);
hinh1.ImageOpened+=hinh1_ImageOpened; //loadingbar will be disappear when this triggered
}
private void hinh1_ImageOpened(object sender, RoutedEventArgs e)
{
loading.IsActive = false; //this will disable the progressring.
}
And XAML:
<StackPanel HorizontalAlignment="Left" Height="597" VerticalAlignment="Top" Width="400">
<Image x:Name="hinh1" Height="488" Stretch="Fill" ImageOpened="hinh1_ImageOpened"/>
<ProgressRing Name="loading" Height="109" IsActive="True" />
</StackPanel>
If you don't have WP8.1 SDK yet, you can get ProgressRing here: http://www.onurtirpan.com/onur-tirpan/english/windows-phone-english/using-progressring-in-windows-phone/

Enabling ScrollViewer HorizontalSnapPoints with bindable collection

I'm trying to create a similar experience as in the ScrollViewerSample from the Windows 8 SDK samples to be able to snap to the items inside a ScrollViewer when scrolling left and right. The implementation from the sample (which works) is like this:
<ScrollViewer x:Name="scrollViewer" Width="480" Height="270"
HorizontalAlignment="Left" VerticalAlignment="Top"
VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto"
ZoomMode="Disabled" HorizontalSnapPointsType="Mandatory">
<StackPanel Orientation="Horizontal">
<Image Width="480" Height="270" AutomationProperties.Name="Image of a cliff" Source="images/cliff.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Image Width="480" Height="270" AutomationProperties.Name="Image of Grapes" Source="images/grapes.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Image Width="480" Height="270" AutomationProperties.Name="Image of Mount Rainier" Source="images/Rainier.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Image Width="480" Height="270" AutomationProperties.Name="Image of a sunset" Source="images/sunset.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Image Width="480" Height="270" AutomationProperties.Name="Image of a valley" Source="images/valley.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</StackPanel>
</ScrollViewer>
The only difference with my desired implementation is that I don't want a StackPanel with items inside, but something I can bind to. I am trying to accomplish this with an ItemsControl, but for some reason the Snap behavior does not kick in:
<ScrollViewer x:Name="scrollViewer" Width="480" Height="270"
HorizontalAlignment="Left" VerticalAlignment="Top"
VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto"
ZoomMode="Disabled" HorizontalSnapPointsType="Mandatory">
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<Image Width="480" Height="270" AutomationProperties.Name="Image of a cliff" Source="images/cliff.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Image Width="480" Height="270" AutomationProperties.Name="Image of Grapes" Source="images/grapes.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Image Width="480" Height="270" AutomationProperties.Name="Image of Mount Rainier" Source="images/Rainier.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Image Width="480" Height="270" AutomationProperties.Name="Image of a sunset" Source="images/sunset.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Image Width="480" Height="270" AutomationProperties.Name="Image of a valley" Source="images/valley.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</ItemsControl>
</ScrollViewer>
Suggestions would be greatly appreciated!
Thanks to Denis, I ended up using the following Style on the ItemsControl and removed the ScrollViewer and inline ItemsPanelTemplate altogether:
<Style x:Key="ItemsControlStyle" TargetType="ItemsControl">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer Style="{StaticResource HorizontalScrollViewerStyle}" HorizontalSnapPointsType="Mandatory">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Getting snap points to work for bound collections can be tricky. For snap points to work immediate child of ScrollViewer should implement IScrollSnapPointsInfo interface. ItemsControl doesn't implement IScrollSnapPointsInfo and consequently you wouldn't see snapping behaviour.
To work around this issue you got couple options:
Create custom class derived from ItemsControl and implement IScrollSnapPointsInfo interface.
Create custom style for items control and set HorizontalSnapPointsType property on ScrollViewer inside the style.
I've implemented former approach and can confirm that it works, but in your case custom style could be a better choice.
Ok, here is the simplest (and standalone) example for horizontal ListView with binded items and correctly working snapping (see comments in following code).
xaml:
<ListView x:Name="YourListView"
ItemsSource="{x:Bind Path=Items}"
Loaded="YourListView_OnLoaded">
<!--Set items panel to horizontal-->
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<!--Some item template-->
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
background code:
private void YourListView_OnLoaded(object sender, RoutedEventArgs e)
{
//get ListView
var yourList = sender as ListView;
//*** yourList style-based changes ***
//see Style here https://msdn.microsoft.com/en-us/library/windows/apps/mt299137.aspx
//** Change orientation of scrollviewer (name in the Style "ScrollViewer") **
//1. get scrollviewer (child element of yourList)
var sv = GetFirstChildDependencyObjectOfType<ScrollViewer>(yourList);
//2. enable ScrollViewer horizontal scrolling
sv.HorizontalScrollMode =ScrollMode.Auto;
sv.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
sv.IsHorizontalRailEnabled = true;
//3. disable ScrollViewer vertical scrolling
sv.VerticalScrollMode = ScrollMode.Disabled;
sv.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled;
sv.IsVerticalRailEnabled = false;
// //no we have horizontally scrolling ListView
//** Enable snapping **
sv.HorizontalSnapPointsType = SnapPointsType.MandatorySingle; //or you can use SnapPointsType.Mandatory
sv.HorizontalSnapPointsAlignment = SnapPointsAlignment.Near; //example works only for Near case, for other there should be some changes
// //no we have horizontally scrolling ListView with snapping and "scroll last item into view" bug (about bug see here http://stackoverflow.com/questions/11084493/snapping-scrollviewer-in-windows-8-metro-in-wide-screens-not-snapping-to-the-las)
//** fix "scroll last item into view" bug **
//1. Get items presenter (child element of yourList)
var ip = GetFirstChildDependencyObjectOfType<ItemsPresenter>(yourList);
// or var ip = GetFirstChildDependencyObjectOfType<ItemsPresenter>(sv); //also will work here
//2. Subscribe to its SizeChanged event
ip.SizeChanged += ip_SizeChanged;
//3. see the continuation in: private void ip_SizeChanged(object sender, SizeChangedEventArgs e)
}
public static T GetFirstChildDependencyObjectOfType<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj is T) return depObj as T;
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = GetFirstChildDependencyObjectOfType<T>(child);
if (result != null) return result;
}
return null;
}
private void ip_SizeChanged(object sender, SizeChangedEventArgs e)
{
//3.0 if rev size is same as new - do nothing
//here should be one more condition added by && but it is a little bit complicated and rare, so it is omitted.
//The condition is: yourList.Items.Last() must be equal to (yourList.Items.Last() used on previous call of ip_SizeChanged)
if (e.PreviousSize.Equals(e.NewSize)) return;
//3.1 get sender as our ItemsPresenter
var ip = sender as ItemsPresenter;
//3.2 get the ItemsPresenter parent to get "viewable" width of ItemsPresenter that is ActualWidth of the Scrollviewer (it is scrollviewer actually, but we need just its ActualWidth so - as FrameworkElement is used)
var sv = ip.Parent as FrameworkElement;
//3.3 get parent ListView to be able to get elements Containers
var yourList = GetParent<ListView>(ip);
//3.4 get last item ActualWidth
var lastItem = yourList.Items.Last();
var lastItemContainerObject = yourList.ContainerFromItem(lastItem);
var lastItemContainer = lastItemContainerObject as FrameworkElement;
if (lastItemContainer == null)
{
//NO lastItemContainer YET, wait for next call
return;
}
var lastItemWidth = lastItemContainer.ActualWidth;
//3.5 get margin fix value
var rightMarginFixValue = sv.ActualWidth - lastItemWidth;
//3.6. fix "scroll last item into view" bug
ip.Margin = new Thickness(ip.Margin.Left,
ip.Margin.Top,
ip.Margin.Right + rightMarginFixValue, //APPLY FIX
ip.Margin.Bottom);
}
public static T GetParent<T>(DependencyObject reference) where T : class
{
var depObj = VisualTreeHelper.GetParent(reference);
if (depObj == null) return (T)null;
while (true)
{
var depClass = depObj as T;
if (depClass != null) return depClass;
depObj = VisualTreeHelper.GetParent(depObj);
if (depObj == null) return (T)null;
}
}
About this example.
Most of checks and errors handling is omitted.
If you override ListView Style/Template, VisualTree search parts must be changed accordingly
I'd rather create inherited from ListView control with this logic, than use provided example as-is in real code.
Same code works for Vertical case (or both) with small changes.
Mentioned snapping bug - ScrollViewer bug of handling SnapPointsType.MandatorySingle and SnapPointsType.Mandatory cases. It appears for items with not-fixed sizes
.