Like in Windows Forms we can add multiple panels in the same Form and based on some condition show and hide particular panel. Is there any control in Xamarin.Forms which can be used like this?
The main reason behind this is, I have 3 tabs on a page. I am using buttons for tabs and not tabbed pages as design of tabbed bar is not what my client wants. So I have 3 pages say Page A, Page B, Page C and each of the page has 3 tabs to go to respective page. If user is on Page A and fills some sort of data(which is not yet saved) and wants to go to Page B and then on Page B he fills in some more details and then without saving data on Page B when he comes back to Page A all the details filled by user on Page A and Page B has to be available.
Hence If I use multiple pages for this then the data will be lost when I redirect to new page. So Is there any way by which I have multiple panels and hide 1st panel when 2nd panel is visible which will not clear any data and hence I can achieve what I want.
You can just hide the panels that aren't being used (using the IsVisible property) - this pulls them out of the visual tree but does not release them from memory.
If you create a Content View for each page, then you can easily use them in your main UI such as in this example. Even though we are hiding the individual panels they will still remain in memory while hidden:
MyView.cs (this could be anything you want in your panels):
using System;
using Xamarin.Forms;
namespace FormsSandbox
{
public class MyView : ContentView
{
public static BindableProperty TextProperty = BindableProperty.Create("Text", typeof(string), typeof(MyView),
String.Empty, BindingMode.Default, null, TextChanged);
public string Text {
get {
return (string)GetValue (TextProperty);
}
set {
SetValue (TextProperty, value);
}
}
private Label _contentLabel;
public MyView ()
{
_contentLabel = new Label {
FontSize = 56,
FontAttributes = FontAttributes.Bold,
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center
};
Content = _contentLabel;
}
static void TextChanged (BindableObject bindable, object oldValue, object newValue)
{
var view = (MyView)bindable;
view._contentLabel.Text = (newValue ?? "").ToString ();
}
}
}
XamlPage.xaml (main UI page):
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:sandbox="clr-namespace:FormsSandbox"
x:Class="FormsSandbox.XamlPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness" iOS="0,20,0,0" Android="0" WinPhone="0"/>
</ContentPage.Padding>
<Grid RowSpacing="0" ColumnSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="1" Clicked="ButtonClicked" x:Name="Button1" Grid.Column="0" />
<Button Text="2" Clicked="ButtonClicked" x:Name="Button2" Grid.Column="1" />
<Button Text="3" Clicked="ButtonClicked" x:Name="Button3" Grid.Column="2" />
<sandbox:MyView Text="1" x:Name="View1" Grid.Row="1" Grid.ColumnSpan="3" />
<sandbox:MyView Text="2" x:Name="View2" Grid.Row="1" Grid.ColumnSpan="3" />
<sandbox:MyView Text="3" x:Name="View3" Grid.Row="1" Grid.ColumnSpan="3" />
</Grid>
</ContentPage>
XamlPage.xaml.cs:
using System;
using Xamarin.Forms;
namespace FormsSandbox
{
public partial class XamlPage : ContentPage
{
public XamlPage ()
{
InitializeComponent ();
SelectButton (Button1);
}
void SelectButton(Button button)
{
View view = null;
if (button == Button1)
view = View1;
if (button == Button2)
view = View2;
if (button == Button3)
view = View3;
View1.IsVisible = View1 == view;
View2.IsVisible = View2 == view;
View3.IsVisible = View3 == view;
Button1.TextColor = (Button1 == button) ? Color.Accent.AddLuminosity(0.18) : (Color)Button.TextColorProperty.DefaultValue;
Button2.TextColor = (Button2 == button) ? Color.Accent.AddLuminosity(0.18) : (Color)Button.TextColorProperty.DefaultValue;
Button3.TextColor = (Button3 == button) ? Color.Accent.AddLuminosity(0.18) : (Color)Button.TextColorProperty.DefaultValue;
Button1.BackgroundColor = (Button1 == button) ? Color.Silver.AddLuminosity(0.18) : Color.Silver.AddLuminosity(0.1);
Button2.BackgroundColor = (Button2 == button) ? Color.Silver.AddLuminosity(0.18) : Color.Silver.AddLuminosity(0.1);
Button3.BackgroundColor = (Button3 == button) ? Color.Silver.AddLuminosity(0.18) : Color.Silver.AddLuminosity(0.1);
}
void ButtonClicked (object sender, EventArgs e)
{
SelectButton ((Button)sender);
}
}
}
You can save this data to a cache and load it from there.
public static class MyDataCache
{
public static MyData MyData { get; } = new MyData();
}
// in your pages
protected override void OnAppearing()
{
base.OnAppearing();
// set data from MyDataCache.MyData
MyProperty = MyDataCache.MyData.MyProperty;
}
protected override void OnDisappearing()
{
base.OnDisappearing();
// set data to MyDataCache.MyData
MyDataCache.MyData.MyProperty = MyProperty;
}
But be aware: It's just a memory cache. If the App gets tombstoned, the data will be lost. You can try this approach first and see if its fits your need. After that, you should store the data in a temporary storage (e.g. with Akavache). You should not rebuild this page navigation behavior with something custom.
Just use a Frame:
<StackLayout>
<Frame x:Name="MyPanelABC">
<Label Text="My Stuff" />
</Frame>
</StackLayout>
private void setupPanelABC(bool isVisiblePanelABC){
MyPanelABC.IsVisible = isVisiblePanelABC;
}
Related
this is probably a simple solution - its just a bit long to explain.
I add custom list view items to a ListView at run-time. Each ListView item has a Name, a Bool and a button. The button when clicked displays a Flyout menu which has subitem menu as shown in the image. The subitem menu should only display the name of all other items not itself. The correct behavior is shown in the first image as the "Item 4" menu button was clicked we only see Items 0 to 3 listed in the submenu.
The issue is that if i navigate to a submenu and then later add new items to the listbox, the new items never appear in the submenu for the older items previously navigated to. Like in the image below, where i clicked Item 1 button but only Item 0 and Item 2 are listed and for some reason Items 3 and 4 are not.
Firstly there is a complete minimum VS2019 solution demonstrating the behavior i'm describing above on GitHub here, though i have summarised what i think are the key bits of code below.
Non-boiler plate XAML header (MainPage.Xaml)
xmlns:local="using:DynamicFlyoutMenuTest.ViewModels"
The main ListView defintion and its DataTemplate as well as a button to add ListView items at run-time:
<StackPanel>
<Button Name="AddCustomListItemBtn" Click="AddCustomListItemBtn_Click">Add Custom ListItem</Button>
<ListView
Name="LayerListBox"
Height="Auto"
BorderBrush="{ThemeResource SystemBaseLowColor}"
BorderThickness="1.0"
ItemsSource="{x:Bind ViewModel.MyCustomListItems}">
<ListView.HeaderTemplate>
<DataTemplate>
<Grid Padding="2" Background="{ThemeResource SystemBaseLowColor}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="190" />
<ColumnDefinition Width="132" />
</Grid.ColumnDefinitions>
<TextBlock Style="{ThemeResource CaptionTextBlockStyle}" Text="Name" />
<TextBlock
Grid.Column="1"
Style="{ThemeResource CaptionTextBlockStyle}"
Text="Active" />
</Grid>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate x:Name="TableDataTemplate" x:DataType="local:MyCustomListItem">
<Grid Height="48" AutomationProperties.Name="{x:Bind ItemName}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="190" />
<ColumnDefinition Width="132" />
<ColumnDefinition Width="132" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
Padding="10"
VerticalAlignment="Center"
Text="{x:Bind ItemName, Mode=OneWay}" />
<CheckBox
Grid.Column="1"
VerticalAlignment="Center"
IsChecked="{x:Bind isEditing, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Button
Name="exportLayerButton"
Grid.Column="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Center">
<Button.Flyout>
<MenuFlyout Opening="MenuFlyout_Opening">
<MenuFlyoutItem
Name="Action1Btn"
Click="Action1Btn_Click"
Text="Action 1" />
<MenuFlyoutItem
Name="Action2Btn"
Click="Action2Btn_Click"
Text="Action 2" />
<MenuFlyoutSubItem x:Name="SubActionsBtn" Text="Choose Sub Action">
<MenuFlyoutItem Name="NoSubActionBtn" Text="None" />
</MenuFlyoutSubItem>
</MenuFlyout>
</Button.Flyout>
<Polygon
Fill="Black"
Points="0,0 6,4,0,8"
Stroke="Black" />
</Button>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
MainPage.xaml.cs - Add Item to List and Update Flyout Sub Menu Items
private void MenuFlyout_Opening(object sender, object e)
{
//make MenuFlyoutSubItem list all Items in ListView except the one triggering this function
var menuFlyout = sender as MenuFlyout;
// get the menu list we want to add to
MenuFlyoutSubItem menuSubItems = menuFlyout.Items.Where(x => x.Name == "SubActionsBtn").FirstOrDefault() as MenuFlyoutSubItem;
// get the active maplayerlistitem (that triggered this menu opening event)
MyCustomListItem myCustomListItem = (menuFlyout.Target as Button).DataContext as MyCustomListItem;
menuSubItems.Items.Clear();
foreach (var targetItem in ViewModel.MyCustomListItems)
{
if (myCustomListItem.ItemName != targetItem.ItemName)
{
var tItem = new MenuFlyoutItem();
tItem.Text = targetItem.ItemName.ToString();
//tItem.Click += new Windows.UI.Xaml.RoutedEventHandler(DoSomethingBtn_Click);
menuSubItems.Items.Add(tItem);
}
}
}
private void AddCustomListItemBtn_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
// Update ListView
var newItem = new MyCustomListItem();
newItem.ItemName = "Item " + ViewModel.MyCustomListItems.Count.ToString();
newItem.isEditing = false;
ViewModel.MyCustomListItems.Add(newItem);
}
MainViewModel.cs
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Microsoft.Toolkit.Mvvm.ComponentModel;
namespace DynamicFlyoutMenuTest.ViewModels
{
public class MainViewModel : ObservableObject
{
public ObservableCollection<MyCustomListItem> MyCustomListItems = new ObservableCollection<MyCustomListItem>();
public MainViewModel()
{
}
}
public class MyCustomListItem : INotifyPropertyChanged
{
public MyCustomListItem()
{
}
private bool _isEditing;
public bool isEditing
{
get { return _isEditing; }
set
{
_isEditing = value;
NotifyPropertyChanged(this, "isEditing");
}
}
private string _itemName;
public string ItemName
{
get { return _itemName; }
set
{
_itemName = value;
NotifyPropertyChanged(this, "ItemName");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged(object sender, string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(sender, e);
}
}
}
}
EDIT
You can view the issue in video at https://www.youtube.com/watch?v=yPNNtsS-n5Q
You can reproduce the issue from the GitHub source by
adding 3 items to the ListView using the "Add..." button.
Navigating to the submenuFlyout of each ListViewItem
Add 2 more Listview Items using the "Add..." button
navigate to the submenuFlyout of the two new items and finally
navigate to submenuFlyout of the original 3 items and see that they haven't updated to reflect the additional ListView items added.
I found a workaround by removing the exsiting MenuFlyoutSubItem and adding a new one each time the Flyout is opened. So it's not ideal, but it does work.
If anyone has as an actual solution, id be happy to mark it as such.
Otherwise here is the workaround:
private void MenuFlyout_Opening(object sender, object e)
{
//make MenuFlyoutSubItem list all Items in ListView except the one triggering this function
var menuFlyout = sender as MenuFlyout;
// get the menu list we want to add to
MenuFlyoutSubItem menuSubItems = menuFlyout.Items.Where(x => x.Name == "SubActionsBtn").FirstOrDefault() as MenuFlyoutSubItem;
// get the active maplayerlistitem (that triggered this menu opening event)
MyCustomListItem myCustomListItem = (menuFlyout.Target as Button).DataContext as MyCustomListItem;
menuFlyout.Items.Remove(menuSubItems);
menuSubItems = new MenuFlyoutSubItem();
menuSubItems.Name = "SubActionsBtn";
menuSubItems.Text = "Choose Sub Action";
foreach (var targetItem in ViewModel.MyCustomListItems)
{
if (myCustomListItem.ItemName != targetItem.ItemName)
{
var tItem = new MenuFlyoutItem();
tItem.Text = targetItem.ItemName.ToString();
//tItem.Click += new Windows.UI.Xaml.RoutedEventHandler(DoSomethingBtn_Click);
menuSubItems.Items.Add(tItem);
}
}
menuFlyout.Items.Add(menuSubItems);
}
I'm working with an item template that should display one or more buttons per item. There are three buttons that I want to be displayed on a horizontal line. Each button has an icon and some text.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="LeftButton"
Text="Left Button"
ImageSource="left.png"
HorizontalOptions="Start"/>
<Button x:Name="CenterButton"
Text="Center Button"
ImageSource="center.png"
HorizontalOptions="Center"/>
<Button x:Name="RightButton"
Text="Right Button"
ImageSource="right.png"
HorizontalOptions="End"/>
</Grid>
This is working good so far. The three buttons display the icon and text and they are aligned left, center and right respectively.
Now, I want the buttons to only display the icons, if the container is not wide enough to display all the text. As far as I understand MVVM, this should be the responsibility of the View.
My intended solution would be something like this:
public partial class ItemTemplate : ContentView
// ContentView is our implementation of a UI element.
{
public ItempTemplate()
{
InitializeComponent();
SizeChanged += HandleSizeChanged;
}
private void HandleSizeChanged(object sender, EventArgs e)
{
if (/* not enough space */)
{
LeftButton.Text = string.Empty;
CenterButton.Text = string.Empty;
RightButton.Text = string.Empty;
}
else
{
LeftButton.Text = "Left Button";
CenterButton.Text = "Center Button";
RightButton.Text = "Right Button";
}
}
}
Is there any way to know if the container is wide enough for all three button? If possible, I'd like to use a dynamic solution, because the button text will eventually be translated.
You can place the code into a custom contentview , and decide to hide/show the text in the event LayoutChanged according to the container's width .
Custom View xaml
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="LeftButton" Grid.Column="0" Text="Left Button" ImageSource="dots.png" HorizontalOptions="Start"/>
<Button x:Name="CenterButton" Grid.Column="1" Text="Center Button" ImageSource="dots.png" HorizontalOptions="Center"/>
<Button x:Name="RightButton" Grid.Column="2" Text="Right Button" ImageSource="dots.png" HorizontalOptions="End"/>
</Grid>
Custom View code behind
public partial class MyView : ContentView
{
public MyView()
{
InitializeComponent();
this.LayoutChanged += MyView_LayoutChanged;
}
private void MyView_LayoutChanged(object sender, EventArgs e)
{
var view = sender as View;
if (view.Width < 200)
{
LeftButton.Text = string.Empty;
CenterButton.Text = string.Empty;
RightButton.Text = string.Empty;
}
else
{
LeftButton.Text = "Left Button";
CenterButton.Text = "Center Button";
RightButton.Text = "Right Button";
}
}
}
Scenario : container is large enough.
xmlns:local="clr-namespace:FormsApp"
<local:MyView/>
Scenario : container is small ,wrapped inside another layout .
<Grid HorizontalOptions="Start" WidthRequest="199" >
<local:MyView/>
</Grid>
I solved my problem by using a custom button implementation (mostly because I needed some other additional features).
The custom button contains an Image and a Label. In addition to the standard button features I need, I added these methods to the code-behind:
public void ExpandText() {
Label.IsVisible = true;
}
public void CollapseText() {
Label.IsVisible = false;
}
public bool IsTextCollapsed() {
return !Label.IsVisible;
}
public double GetWidthAsExpanded() {
return Image.Width + Label.Width;
}
In the container's code-behind I check if the button's width fits within its container and collapse/expand accordingly. For that to work, I added containers for each button.
public ItemTemplate() {
InitializeComponent();
LayoutChanged += HandleLayoutChanged;
}
private static void HandleLayoutChanged(object sender, EventArgs e)
{
if (!(sender is ItemTemplate itemTemplate))
{
return;
}
if (itemTemplate.ButtonContainerLeft.Width > itemTemplate.ButtonLeft.GetWidthAsExpanded()
&& itemTemplate.ButtonContainerCenter.Width > itemTemplate.ButtonCenter.GetWidthAsExpanded()
&& itemTemplate.ButtonContainerRight.Width > itemTemplate.ButtonRight.GetWidthAsExpanded())
{
ExpandAllButtons(itemTemplate);
}
else
{
CollapseAllButtons(itemTemplate);
}
}
Because I added ExpandText and CollapseText earlier, I don't have to "remember" what the text inside the button was, because I just collapse the label within the button. GetWidthAsExpanded will always return the necessary width of the button, even if it is collapsed.
side-note 1: I could've just added the width-check within the custom button implementation, but not every ItemTemplate has all buttons and if any label is collapsed, all labels should be collapsed.
side-note 2: I needed button containers either way, because the left button will either be "Mark as Read" or "Mark as Unread" depending on the state of the ItemTemplate data context. So there are actually two buttons in the first container.
I am creating autocomplete textview in xamarin forms by this using this sample. But in this example they are using AutoCompleteTextView in mainActivity.cs onCreate(). How could I use the same code in my xaml forms
CODE IS:
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "Main" layout resource
SetContentView (Resource.Layout.Main);
AutoCompleteTextView textView = FindViewById<AutoCompleteTextView> (Resource.Id.autocomplete_country);
var adapter = new ArrayAdapter<String> (this, Resource.Layout.list_item, COUNTRIES);
textView.Adapter = adapter;
}
Thank you.
You can't use Android samples (including Xamarin.Android) directly in Xamarin.Forms. Those are different technologies.
Xamarin.Forms can also runs on iOS (even if you don't want it to) and iOS won't run Android specific code, that's the main reason why it is impossible.
Other than that you may build Xamarin.Forms controls from native controls using custom renderers. So basically you could make the above sample work on Xamarin.Forms, but with lot of knowledge and hard work, a lot more code is needed than the sample above.
I did something like this in my Xamarin.Forms project, which was 100% shared by Android and iOS - no custom renderers. This example uses the MVVM pattern with some use of the code-behind. My view model contains an IList of object which the ListView binds to. It is updated when the user presses three or more characters with a query expression.
private IList<myObject> results;
public IList<myObject> QueryResults
{
get
{
return results;
}
set
{
SetProperty(ref results, value);
}
}
Within the OnTextChanged handler I run the query expression and populate QueryResults on every key stroke. This might not be that efficient, but it performs well.
So the view mark up and code-behind is something like this:
<StackLayout>
<Label Style="{StaticResource formLabel}" Text="My Searchable List" />
<!-- from poc -->
<Grid WidthRequest="550">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="AUTO" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="350" />
</Grid.ColumnDefinitions>
<Frame Grid.Row="0" Style="{StaticResource InputFrame}" HeightRequest="49">
<Entry x:Name="SearchText" Style="{StaticResource formLabel}" WidthRequest="550" HeightRequest="45" Text="{Binding SearchString, Mode=TwoWay}" TextChanged="Handle_TextChanged" />
</Frame>
<StackLayout Grid.Row="1" Orientation="Horizontal">
<Frame x:Name="MyObjectFrame" Style="{StaticResource InputFrame}" HeightRequest="{Binding ListHeight}" HasShadow="true">
<ListView x:Name="MyObjectList" ItemsSource="{Binding ResultantMyObjects}" ItemSelected="OnItemSelected" HeightRequest="{Binding ListHeight}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Name}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Frame>
</StackLayout>
with the Handle_TextChanged in the code-behind:
void Handle_TextChanged(object sender, Xamarin.Forms.TextChangedEventArgs e)
{
if (e.NewTextValue.Length > 2)
{
(BindingContext as SampleDetailsViewModel).MySIteSearchResults(e.NewTextValue);
this.ForceLayout();// force the change in heightrequest for ListView
MyObjectList.IsVisible = true;
MyObjectFrame.IsVisible = true;
}
else
{
MyObjectList.IsVisible = false;
MyObjectFrame.IsVisible = false;
}
}
In the view model, I update the property above, note the return value really isn't used in this not-yet-perfect example:
public List<MyObjectDTO> MyObjectSearchResults(string keystrokes)
{
//TODO: encapsulate in a View
List<MyObjectDTO> searchResults = null;
IEnumerable<MyObjectDTO> queryResults;
queryResults = from site in MyObjects
where site.Name.ToLower().Contains(keystrokes.ToLower())
select site;
if (string.IsNullOrEmpty(SearchString))
{
QueryResults = MyObjects;
}
else
{
QueryResults = queryResults.ToList<MyObjectDTO>();
ListHeight = QueryResults.Count * 45; //TODO: detect size. magic number of 45 limits the height.
}
return searchResults;
}
NOTE: There might be some errors, as I had to scrub some code.
First of all I am new to UWP and I have already searched almost everywhere (using Google and Stackoverflow) for the answer but couldn't find the answer for my problem.
So, Here is the problem:
I planned to create a pixel paint app that has tab function like Edge (utilizing title bar) for UWP using Visual Studio 2017 and Target Sdk: Creators Update.
I wanted to move the custom title bar I made to the content view when the app in fullscreen condition.
I wanted to move from here (windows title bar, this is just the button XAML code, I'm not including the tab bar XAML code because it's a commercial project):
<Grid x:Name="btnMenuPlace1" Grid.Column="0">
<Grid x:Name="btnMenuPlaceContent" Background="{StaticResource SystemControlHighlightListAccentMediumBrush}">
<Button x:Name="btnMenu" FontFamily="Segoe MDL2 Assets" Content=""
Width="50" Height="50" Background="Transparent" Click="btnMenu_Click"/>
</Grid>
</Grid>
To here (user view):
<Grid x:Name="btnMenuPlace2" Grid.Column="0">
</Grid>
Both parent of those Grid is an another Grid using Grid.ColumnDefinitions like this:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
And here's my C# Code:
private void WindowSizeChanged(object sender, WindowSizeChangedEventArgs e)
{
var appView = ApplicationView.GetForCurrentView();
if (appView.IsFullScreenMode)
{
Utility.RemoveChild(btnMenuPlaceContent);
btnMenuPlace2.Children.Add(btnMenuPlaceContent);
Utility.RemoveChild(tabBarPlaceContent);
tabBarPlace2.Children.Add(tabBarPlaceContent);
}
else
{
Utility.RemoveChild(btnMenuPlaceContent);
btnMenuPlace1.Children.Add(btnMenuPlaceContent);
Utility.RemoveChild(tabBarPlaceContent);
tabBarPlace1.Children.Add(tabBarPlaceContent);
}
e.Handled = true;
}
And here is my Utility RemoveChild Code:
public static void RemoveChild(DependencyObject parent, UIElement child)
{
var parentAsPanel = VisualTreeHelper.GetParent(child);
if (parentAsPanel != null)
{
parentAsPanel.Children.Remove(child);
return;
}
var parentAsContentPresenter = parent as ContentPresenter;
if (parentAsContentPresenter != null)
{
if (parentAsContentPresenter.Content == child)
{
parentAsContentPresenter.Content = null;
}
return;
}
var parentAsContentControl = parent as ContentControl;
if (parentAsContentControl != null)
{
if (parentAsContentControl.Content == child)
{
parentAsContentControl.Content = null;
}
return;
}
}
This is my app looks like before entered the fullscreen mode:
So the problem is whenever the app entered the fullscreen mode, the child does move to the new parent, but the button is not there only the background color of the grid remaining and I can't click any of them (not a single click event work), take a look:
And when I switched back to not fullscreen view the proggressbar loading on the new tab not shown.
I don't know which one I did was wrong XAML or the C# code.
Any help would be appreciated.
P.S. I'm Indonesian, so maybe there is something wrong with my sentence, hopefully You are understand what I'm talking about.
There are somethings wrong with your code snippet. For example, RemoveChild method has two parameters but you only provide one when you invoking it. And without assign the parentAsPanel variable type, you cannot get the Children property.
Since the code is not completed, after code updated and add some other code needed I can run your code snippet correctly and cannot reproduce the issue above. Here is my completed testing code:
XAML
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<Grid x:Name="btnMenuPlace1" Grid.Column="0" Grid.Row="0">
<Grid x:Name="btnMenuPlaceContent" Background="{StaticResource SystemControlHighlightListAccentMediumBrush}">
<StackPanel Orientation="Horizontal">
<Button x:Name="btnMenu" FontFamily="Segoe MDL2 Assets" Content="" Width="50" Height="50" Background="Transparent" />
<!--<local:CustomTitleBar Width="200" Height="50"></local:CustomTitleBar>-->
</StackPanel>
</Grid>
</Grid>
<Grid x:Name="btnMenuPlace2" Grid.Column="1" Grid.Row="1"/>
<TextBlock Text="text" x:Name="txtresult"></TextBlock>
<Button x:Name="ToggleFullScreenModeButton" Margin="0,10,0,0" Click="ToggleFullScreenModeButton_Click">
<SymbolIcon x:Name="ToggleFullScreenModeSymbol" Symbol="FullScreen" />
</Button>
</StackPanel>
</Grid>
Code behind
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
Window.Current.SetTitleBar(btnMenuPlace1);
Window.Current.SizeChanged += Current_SizeChanged;
}
private void Current_SizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
var appView = ApplicationView.GetForCurrentView();
if (appView.IsFullScreenMode)
{
RemoveChild(btnMenuPlace1, btnMenuPlaceContent);
btnMenuPlace2.Children.Add(btnMenuPlaceContent);
}
else
{
RemoveChild(btnMenuPlace2, btnMenuPlaceContent);
btnMenuPlace1.Children.Add(btnMenuPlaceContent);
}
e.Handled = true;
}
public void RemoveChild(DependencyObject parent, UIElement child)
{
Grid parentAsPanel = VisualTreeHelper.GetParent(child) as Grid;
if (parentAsPanel != null)
{
parentAsPanel.Children.Remove(child);
return;
}
var parentAsContentPresenter = parent as ContentPresenter;
if (parentAsContentPresenter != null)
{
if (parentAsContentPresenter.Content == child)
{
parentAsContentPresenter.Content = null;
}
return;
}
var parentAsContentControl = parent as ContentControl;
if (parentAsContentControl != null)
{
if (parentAsContentControl.Content == child)
{
parentAsContentControl.Content = null;
}
return;
}
}
private void ToggleFullScreenModeButton_Click(object sender, RoutedEventArgs e)
{
var view = ApplicationView.GetForCurrentView();
if (view.IsFullScreenMode)
{
view.ExitFullScreenMode();
}
else
{
if (view.TryEnterFullScreenMode())
{
txtresult.Text = "full screen";
}
else
{
txtresult.Text = "no full screen";
}
}
}
}
My testing environment is OS build 15063. If you still have issues please provide the minimal reproduced project. You may just try to reproduce the issue on my testing demo. More details please reference the official sample.
Sorry it was My mistake, that above code I post is actually working (just some of the code wrongly copied, like for example the parameter on the utility code is not necessary).
The false is on it's parent, i forgot to add row definition on the second place (btnPlace2) parent.
Now it works and looks great now :)
Here is some picture of em:
On FullScreen Mode:
Thanks to anyone answering and voting this question up.
Best regards,
andr33ww
I'm pretty stuck right now, i'm gonna explain my problem and what i want.
In my solution i have a mainWindow, in that MainWindow i call the first userControl Who is situated in an userControlLibrary. I'ts a menu with button. I want when i click on the first button of the first userControl, i want put the visibility of the second usercontrol to visible (too situated in the userControlLibrary). But i try many things but no one works.
The first userControl is UC_MenuSlider and UC_Start_Study is the second who have to be visibile after click on the button on the first one. At launch UC_Start_Study is hidden.
This is a part of the code of my Mainwindow:
<Grid Name="MainGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<UserControlLibrary:UC_StartStudy x:Name="UC_Start_Study" Grid.Column="1" Height="Auto" Width="Auto" Margin="70 0 0 0" Visibility="Hidden"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.1*" MaxWidth="240" MinWidth="240" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<UserControlLibrary:UC_MenuSlider x:Name="UC_MenuSlider" Grid.Column="0"/>
</Grid>
</Grid>
A part of the code of my first UserControl (UC_MenuSlider):
<Grid Name="Grid_Menu" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button x:Name="Start_Study" Grid.Row="0" Grid.Column="0" Margin="0" Content="Start Study" FontSize="16" Click="Start_Study_Click">
</Button>
</Grid>
At first a basic event,just an event click in my first userControl. with code behind like that:
public void Start_Study_Click(object sender, RoutedEventArgs e)
{
var startStudy = new UserControlLibrary.UC_StartStudy();
startStudy.Visibility = Visibility.Visible;
}
Don't works. Then i use 'RoutedEvent' But I don't really understand who it works.
I hope my question was enough clear, thanks in advance for your anwsers
The problem is because you are creating a new UC_StartStrudy and set its Visibility to Visible. What you really need is to set Visibility of the one in your XAML: UC_Start_Study
public void Start_Study_Click(object sender, RoutedEventArgs e)
{
UC_Start_Study.Visibility = Visibility.Visible;
}
And you could also use XAML databinding the Visibility property of your UC_StartStrudy, and set its value in your code:
XAML:
<Window.Resourses>
<BooleanToVisibilityConverter x:Key="BooltoVisible" />
</Window.Resourse>
.....
<UserControlLibrary:UC_StartStudy x:Name="UC_Start_Study" Grid.Column="1" Height="Auto" Width="Auto" Margin="70 0 0 0" Visibility="{Binding IsUCStartStudyVisible, Converter={StaticResource BooltoVisible}}"/>
Code (remember to implement INotifyPropertyChanged ):
//implement INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChange(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
//property for data binding
private bool _isucstartstudyvisible = false;
public bool IsUCStartStudyVisible
{
get{return _isucstartstudyvisible;}
set{_isucstartstudyvisible=value; RaisePropertyChange("IsUCStartStudyVisible");}
}
//your event to change the visibility
public void Start_Study_Click(object sender, RoutedEventArgs e)
{
IsUCStartStudyVisible=true;
}
I don't understand why you are taking a new instance of UC_StartStudy() as you have already added this in your MainWindow.
Can't you simply turn the visibility of UC_Start_Study as visible within the code.
Let me show you how you can do this.
try
public void Start_Study_Click(object sender, RoutedEventArgs e)
{
this.UC_Start_Study.Visibility = Visibility.Visible;
}