I'm trying in every way to get out of the loop that must create multiple RichTextBlockOverflow controls based on arbitrary input text length but without success. The HasOverflowContent property doesn't update either synchronously or asynchronously.
The variable bool "ThereIsText" I can not understand when and how to make it false to stop the loop.
The link with the text to paste in the paragraph "Run" is: text to paste.
MainPage.xaml:
<Page
x:Class="Text_Viewer_Test_UWP.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Text_Viewer_Test_UWP"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="Menù" HorizontalAlignment="Left" Width="290" Padding="0" Margin="0,21,0,0">
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" x:Name="btnLoadText" Click="btnLoadText_Click" Content="Display text" HorizontalAlignment="Center" VerticalAlignment="Center" Width="270" Foreground="White" Height="32"/>
<TextBlock Grid.Row="1" x:Name="txtPage" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Grid>
<Grid x:Name="BaseGrid" Margin="320,10,30,10" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Black">
<ScrollViewer x:Name="PageViewer" Background="White" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Visible" VerticalScrollMode="Disabled" HorizontalScrollMode="Enabled">
<StackPanel x:Name="StackViewer" VirtualizingStackPanel.VirtualizationMode="Recycling" Orientation="Horizontal"/>
</ScrollViewer>
</Grid>
</Grid>
MainPage.xaml.cs:
public sealed partial class MainPage : Page
{
RichTextBlock TextOneRich = new RichTextBlock() { Margin = new Thickness(20) };
List<RichTextBlockOverflow> TextList = new List<RichTextBlockOverflow>();
bool ThereIsText = true;
public MainPage()
{
this.InitializeComponent();
StackViewer.Children.Add(TextOneRich);
TextOneRich.Width = 400;
TextOneRich.TextAlignment = TextAlignment.Justify;
}
private async void btnLoadText_Click(object sender, RoutedEventArgs e)
{
TextList.Clear();
TextOneRich.Blocks.Clear();
StackViewer.Children.Clear();
StackViewer.Children.Add(TextOneRich);
Paragraph paragraphText = new Paragraph();
paragraphText.Inlines.Clear();
paragraphText.Inlines.Add(new Run { Text = "PasteTextHere" });
await Task.Run(async () =>
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
TextOneRich.Blocks.Add(paragraphText);
});
}).ContinueWith(async t =>
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
TextList.Add(new RichTextBlockOverflow() { Width = 400, Margin = new Thickness(20) });
StackViewer.Children.Add(TextList[0]);
TextOneRich.OverflowContentTarget = TextList[0];
});
});
await Task.Run(async () =>
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
while (ThereIsText)
{
await Task.Run(async () =>
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
TextList.Add(new RichTextBlockOverflow() { Width = 400, Margin = new Thickness(20) });
StackViewer.Children.Add(TextList[TextList.Count - 1]);
TextList[TextList.Count - 2].OverflowContentTarget = TextList[TextList.Count - 1];
txtPage.Text = TextList.Count.ToString();
});
});
}
});
});
}
}
If you need to do a lot of manipulation of UI objects, and you want to keep the UI responsive while you do that(1) then you can generally just await for a single millisecond, which will allow the UI to process any input messages etc.
Trying to access the HasOverflowContent property is problematic since it requires a layout pass to complete, and that could take an arbitrary amount of time. We could just await an arbitrary amount of time - say 50ms - but that wouldn't be ideal. Instead, you can use a technique similar to the one from "Waiting for XAML layout to complete" with a slight adjustment.
This XAML and code adds 1000 lines of text to a set of RichTextBlock / RichTextBlockOverflow controls and does so while keeping the UI responsive (the ball keeps moving, and you can scroll the list at any time):
XAML:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Margin="20" HorizontalAlignment="Stretch" x:Name="container">
<Ellipse Width="20" Height="20" Margin="0, 5" Fill="red"
x:Name="animation" HorizontalAlignment="Left"/>
<Button Content="Go" Click="Go" Margin="0,0,0,5"/>
<ScrollViewer MaxHeight="500">
<StackPanel x:Name="thePanel"/>
</ScrollViewer>
</StackPanel>
</Grid>
Code:
public static class Extensions
{
// This helper function is essentially the same as this answer:
// https://stackoverflow.com/a/14132711/4184842
//
// It adds an additional forced 1ms delay to let the UI thread
// catch up.
public static Task FinishLayoutAsync(this FrameworkElement element)
{
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
// Setup handler that will be raised when layout has completed.
EventHandler<object> handler = null;
handler = (s, a) =>
{
element.LayoutUpdated -= handler;
tcs.SetResult(true);
};
element.LayoutUpdated += handler;
// Await at least 1 ms (to force UI pump) and until the Task is completed
// If you don't wait the 1ms then you can get a 'layout cycle detected' error
// from the XAML runtime.
return Task.WhenAll(new[] { Task.Delay(1), tcs.Task });
}
}
public sealed partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
// Simple animation to show the UI is not frozen
BadUiAnimation_DontDoThis();
}
// Very VERY bad way of doing animation, but it shows
// that the UI is still responsive. Normally you should
// use StoryBoards to do animation.
void BadUiAnimation_DontDoThis()
{
DispatcherTimer dt = new DispatcherTimer();
dt.Interval = TimeSpan.FromMilliseconds(33);
int delta = 4;
const int width = 20;
dt.Tick += (s, a) =>
{
var leftOffset = animation.Margin.Left;
if (leftOffset + delta < 0)
{
delta *= -1;
leftOffset = 0;
}
else if (leftOffset + delta + width > container.ActualWidth)
{
delta *= -1;
leftOffset = container.ActualWidth - width;
}
else
{
leftOffset += delta;
}
animation.Margin = new Thickness(leftOffset, 5, 0, 5);
};
dt.Start();
}
private async void Go(object sender, RoutedEventArgs e)
{
// Helper function
void AppendSimpleString(string s)
{
RichTextBlock rtb = new RichTextBlock();
rtb.Blocks.Add(CreateParagraphWithText(s));
thePanel.Children.Add(rtb);
}
// Another helper function
Paragraph CreateParagraphWithText(string s)
{
var p = new Paragraph();
var r = new Run();
r.Text = s;
p.Inlines.Add(r);
return p;
}
// Disable the button so you can't click it again until the
// insertion is over
(sender as Button).IsEnabled = false;
thePanel.Children.Clear();
AppendSimpleString($"Begin...{Environment.NewLine}");
// Generate some dummy strings to add to the page
var strings = new StringBuilder();
for (int i = 0; i < 1000; i++)
strings.Append($"This is line {i + 1}{Environment.NewLine}");
string text = strings.ToString();
// Create initial block with far too much text in it
var source = new RichTextBlock();
source.MaxHeight = 100;
source.Blocks.Add(CreateParagraphWithText(text));
thePanel.Children.Add(source);
// Create the first overflow and connect it to the original textblock
var prev = new RichTextBlockOverflow
{
MaxHeight = 100,
Margin = new Thickness(0, 10, 0, 0)
};
thePanel.Children.Add(prev);
source.OverflowContentTarget = prev;
// Wait for layout to complete so we can check the
// HasOverflowContent property
await prev.FinishLayoutAsync();
// Keep creating more overflows until there is no content left
while (prev.HasOverflowContent)
{
var next = new RichTextBlockOverflow
{
MaxHeight = 100,
Margin = new Thickness(0, 10, 0, 0)
};
thePanel.Children.Add(next);
prev.OverflowContentTarget = next;
// Wait for layout to complete, which will compute whether there
// is additional overflow (or not)
await prev.FinishLayoutAsync();
prev = next;
};
AppendSimpleString($"Done!{Environment.NewLine}");
// Enable interaction with the button again
(sender as Button).IsEnabled = true;
}
}
(1): Note that you probably want to do something to limit interaction with your UI while this is happening, which might require you to disable some controls or otherwise make sure the user doesn't mess with your app's state. The sample does this by disabling and then re-enabling the button.
Related
I am trying to write a game for myself using Xamarin. The problem is that I can't make the colors dynamically change after the start button is pressed. At first I tried to do it through the BackgroundColor property, but because it didn't work, I decided to use dynamic resources, but that doesn't work either. Please help me find a mistake in the code or algorithm.
P.s
The idea of the game is this: to reproduce a sequence of colors from memory, the difficulty gradually increases: at first only one button is highlighted, then there are already two buttons, and so on. Victory is achieved if you accurately reach the 20th stage (reproduce a sequence of 20 colors) and complete it.
P.p.s
I ran the app on my phone - Xiaomi Poco X3 NFC, my OS is MIUI 12 (Android 10).
MainPage.xaml.cs
using System;
using System.Threading;
using Xamarin.Forms;
namespace JustRepeat
{
public partial class MainPage : ContentPage
{
public readonly MethodsCollection methodsCollection;
public readonly Button[] buttonsMas;
public MainPage()
{
InitializeComponent();
methodsCollection = new MethodsCollection(this);
buttonsMas = new Button[] { one, two, three, four, five, six, seven, eight, nine };
}
private void Button_Clicked(object sender, EventArgs e)
{
methodsCollection.PlaySequence();
startstop.IsEnabled = false;
}
private void Buttons_Clicked(object sender, EventArgs e)
{
bool result = methodsCollection.CheckSequence((Button)sender, out int currStg);
if (!result)
{
DisplayAlert("Notification", $"You lose.\nThe last passed stage: {currStg}.", "OK");
startstop.IsEnabled = true;
return;
}
else if (result & currStg == 20)
{
DisplayAlert("Notification", "You won!", "OK");
startstop.IsEnabled = true;
}
}
}
public class MethodsCollection
{
private readonly MainPage mainPage;
private Color[] colors;
private int[] sequence;
private int currentStage = 1;
private int currentMember = 0;
public MethodsCollection(MainPage mP)
{
mainPage = mP;
}
private int[] GenerateSequence(int currentNumber)
{
Random random = new Random();
int[] posMas = new int[currentNumber];
for (int i = 0; i < posMas.Length; i++)
{
posMas[i] = random.Next(1, 10);
}
return posMas;
}
public void PlaySequence()
{
Random random = new Random();
sequence = GenerateSequence(currentStage);
colors = new Color[currentStage];
for (int i = 0; i < sequence.Length; i++)
{
colors[i] = Color.FromRgb(random.Next(0, 256), random.Next(0, 256), random.Next(0, 256));
mainPage.Resources[string.Format("{0}", sequence[i])] = colors[i];
Thread.Sleep(1000);
mainPage.Resources[string.Format("{0}", sequence[i])] = Color.LightGray;
}
}
public bool CheckSequence(Button btn, out int stage)
{
int pos = 0;
for (int i = 0; i < mainPage.buttonsMas.Length; i++)
{
if (btn == mainPage.buttonsMas[i])
{
pos = i;
}
}
if (currentStage == 20)
{
if (pos == sequence[currentMember])
{
SetColor();
ClearVariables();
stage = currentStage;
currentStage = 1;
return true;
}
ClearVariables();
stage = currentStage - 1;
currentStage = 1;
return false;
}
if (currentStage - currentMember == 1)
{
if (pos == sequence[currentMember])
{
SetColor();
ClearVariables();
stage = currentStage++;
return true;
}
ClearVariables();
stage = currentStage - 1;
currentStage = 1;
return false;
}
if (pos == sequence[currentMember])
{
currentMember++;
stage = currentStage;
return true;
}
else
{
ClearVariables();
stage = currentStage - 1;
currentStage = 1;
return false;
}
}
private void SetColor()
{
mainPage.Resources[string.Format("{0}", sequence[currentMember])] = colors[currentMember];
Thread.Sleep(1000);
mainPage.Resources[string.Format("{0}", sequence[currentMember])] = Color.LightGray;
}
private void ClearVariables()
{
currentMember = 0;
sequence = null;
colors = null;
}
}
}
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="JustRepeat.MainPage">
<ContentPage.Resources>
<ResourceDictionary>
<Color x:Key="1">LightGray</Color>
<Color x:Key="2">LightGray</Color>
<Color x:Key="3">LightGray</Color>
<Color x:Key="4">LightGray</Color>
<Color x:Key="5">LightGray</Color>
<Color x:Key="6">LightGray</Color>
<Color x:Key="7">LightGray</Color>
<Color x:Key="8">LightGray</Color>
<Color x:Key="9">LightGray</Color>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<Grid VerticalOptions="FillAndExpand" >
<Button BackgroundColor="{DynamicResource Key=1}" Clicked="Buttons_Clicked" Grid.Column="0" Grid.Row="0" x:Name="one"/>
<Button BackgroundColor="{DynamicResource Key=2}" Clicked="Buttons_Clicked" Grid.Column="1" Grid.Row="0" x:Name="two"/>
<Button BackgroundColor="{DynamicResource Key=3}" Clicked="Buttons_Clicked" Grid.Column="2" Grid.Row="0" x:Name="three"/>
<Button BackgroundColor="{DynamicResource Key=4}" Clicked="Buttons_Clicked" Grid.Column="0" Grid.Row="1" x:Name="four"/>
<Button BackgroundColor="{DynamicResource Key=5}" Clicked="Buttons_Clicked" Grid.Column="1" Grid.Row="1" x:Name="five"/>
<Button BackgroundColor="{DynamicResource Key=6}" Clicked="Buttons_Clicked" Grid.Column="2" Grid.Row="1" x:Name="six"/>
<Button BackgroundColor="{DynamicResource Key=7}" Clicked="Buttons_Clicked" Grid.Column="0" Grid.Row="2" x:Name="seven"/>
<Button BackgroundColor="{DynamicResource Key=8}" Clicked="Buttons_Clicked" Grid.Column="1" Grid.Row="2" x:Name="eight"/>
<Button BackgroundColor="{DynamicResource Key=9}" Clicked="Buttons_Clicked" Grid.Column="2" Grid.Row="2" x:Name="nine"/>
</Grid>
<Button BackgroundColor="DarkGray" Text="Старт" Clicked="Button_Clicked" VerticalOptions="Fill" x:Name="startstop"/>
</StackLayout>
</ContentPage>
Trying to do "anything" like setting the color of a button to displaying an error in xamarin needs to be done in the correct place in the correct way. In your code setting the color of the buttons is irrelevant to your Application because you do not invoke the changes.
Setting the color with:
Device.BeginInvokeOnMainThread(() =>
{
// Your method to change the color.
button.BackgroundColor = Color.Black; // Or whatever.
});
If you need a DisplayAlert for example you can do this async too.
Device.BeginInvokeOnMainThread(async () => // <-----
{
// You await the message
await DisplayAlert("Attention", "Color changed!", "OK);
});
Resolved this to the comments, but i posted an answer for future reference.
Changing the value of a resource AFTER the page has been loaded won't affect the button color - it has already been read from the resource.
Instead, give the button an x:Name, so you can set its background color directly.
xaml:
<Button x:Name="button1" ... />
cs:
button1.BackgroundColor = ...;
OR might Device.BeginInvokeOnMainThread, as shown in stersym's answer.
(I added a new answer because that answer did not show x:Name.)
IMPORTANT: Intellisense won't know about button1 until after you build. What I do is add x:Name to XAML, build project, then add cs code that uses the name.
I develop one-page app. This is XAML of MainPage
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical" Grid.Row="0">
<AppBar x:Name="MenuAppBar" IsOpen="True">
<StackPanel Orientation="Horizontal">
<AppBarButton Icon="Add" Label="Добавить лексемы" Name="AddLexemesFromFolder" Click="OpenFolderAndGetLexemes_Click" HorizontalAlignment="Left"/>
<AppBarButton Icon="Save" Label="Сохранить лексемы" Name="SaveLexemes" Click="SaveLexemes_Click" HorizontalAlignment="Left"/>
</StackPanel>
</AppBar>
</StackPanel>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" VerticalScrollMode="Enabled">
<Grid x:Name="GridLexemesViewer" HorizontalAlignment="Stretch"/>
</ScrollViewer>
</Grid>
When I pressed "AddLexemesFromFolder" button more than two times, GridLexemesViewer is getting smaller over and over.
This is OpenFolderAndGetLexemes code
private async void OpenFolderAndGetLexemes_Click(object sender, RoutedEventArgs routedEventArgs)
{
await StartSaveLexemes();
var folderPicker = new Windows.Storage.Pickers.FolderPicker();
folderPicker.FileTypeFilter.Add("*");
Windows.Storage.StorageFolder folder = await folderPicker.PickSingleFolderAsync();
if (folder != null)
{
StorageApplicationPermissions.FutureAccessList.AddOrReplace("PickedFolderToken", folder);
await Task.Run(() => StartNewSessionForGetLexemes(folder.Path));
InitializeGrid();
}
}
I use "InitializeGrid" method for clear Children in GridLexemesViewer, use CreateRowsAndColumns and put TextBox with content to GridLexemesViewer.
This is code of InitializeGrid and CreateRowsAndColumns()
private void InitializeGrid()
{
GridLexemesViewer.Children.Clear();
CreateRowsAndColumns();
int index = 1;
foreach (var lexem in CurrentSession.Lexemes)
{
foreach (var item in lexem.Value)
{
Binding binding = new Binding
{
Source = item,
Path = new PropertyPath("Value"),
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
TextBox textBox = new TextBox { TextWrapping = TextWrapping.Wrap };
BindingOperations.SetBinding(textBox, TextBox.TextProperty, binding);
GridLexemesViewer.Children.Add(textBox);
Grid.SetColumn(textBox, CurrentSession.Languages.IndexOf(item.Language) + 1);
Grid.SetRow(textBox, index);
}
index++;
}
}
private void CreateRowsAndColumns()
{
int indexRow = 1;
int indexColumn = 1;
RowDefinition firstRowDefinition = new RowDefinition();
ColumnDefinition firstColumnDefinition = new ColumnDefinition { Width = GridLength.Auto };
GridLexemesViewer.ColumnDefinitions.Add(firstColumnDefinition);
GridLexemesViewer.RowDefinitions.Add(firstRowDefinition);
foreach (var key in CurrentSession.Lexemes.Keys)
{
RowDefinition rowDefinition = new RowDefinition();
GridLexemesViewer.RowDefinitions.Add(rowDefinition);
TextBlock textBlock = new TextBlock{Text = key};
GridLexemesViewer.Children.Add(textBlock);
Grid.SetRow(textBlock, indexRow);
indexRow++;
}
foreach (var language in CurrentSession.Languages)
{
ColumnDefinition columnDefinition = new ColumnDefinition { Width = new GridLength(1.0, GridUnitType.Star)};
GridLexemesViewer.ColumnDefinitions.Add(columnDefinition);
TextBlock textBlock = new TextBlock {Text = language};
GridLexemesViewer.Children.Add(textBlock);
Grid.SetRow(textBlock, 0);
Grid.SetColumn(textBlock, indexColumn);
indexColumn++;
}
}
This GIF shows how to reproduce bug
The problem is that you are calling CreateRowsAndColumns() each time but not removing the Rows and Columns from previous run. Using Grid.Clear() only deletes the children controls in the Grid, but the Grid.RowDefinitions and Grid.ColumnDefinitions stay intact.
To fix this, clear both definitions at the start of CreateRowsAndColumns():
GridLexemesViewer.RowDefinitions.Clear();
GridLexemesViewer.ColumnDefinitions.Clear();
However, definitely consider using the DataGrid control from the Windows Community Toolkit as it should have all the features you need and has better maintainability and performance then a custom Grid, especially for bigger data.
Problem while programmatically generating buttons in a user control of windows phone, and using this user control to mainpage.xaml but there are no buttons shown when application runs.
here is the code snippet which i am using, Thanks !
usercontrol.xaml:
<ScrollViewer >
<StackPanel x:Name="Panel">
<ContentControl x:Name="container"></ContentControl>
</StackPanel>
</ScrollViewer>
usercontrol.xaml.cs:
public LoginInterfaceControl()
{
InitializeComponent();
this.container = new ContentControl();
this.Panel = new StackPanel();
}
public LoginInterfaceControl(string Api_key)
{
InitializeComponent();
this.Panel = new StackPanel();
this.container = new ContentControl();
loginWP_DownloadString(Api_key);
}
public async void loginWP_DownloadString(string key)
{
InitializeComponent();
string cont;
using (HttpClient client = new HttpClient())
{
var result = await client.GetAsync("http://cdn.loginradius.com/interface/json/" + key + ".json");
if (result.StatusCode == HttpStatusCode.OK)
{
cont = await result.Content.ReadAsStringAsync();
MessageBox.Show(cont);
}
else
{
cont = await result.Content.ReadAsStringAsync();
MessageBox.Show(cont);
}
if (!string.IsNullOrEmpty(cont))
{
var root1 = JsonConvert.DeserializeObject<RootObject>(cont);
int no = 1;
foreach (var provider in root1.Providers)
{
no++;
Button newBtn = new Button()
{
Content = provider.Name.ToString(),
Name = provider.Name.ToString(),
//Width = 88,
//Height = 77,
Visibility = System.Windows.Visibility.Visible,
//Margin = new Thickness(5 + 20, 5, 5, 5),
Background = new SolidColorBrush(Colors.Black),
VerticalAlignment =VerticalAlignment.Center,
Opacity=0.5
};
newBtn.Click += google_click;
System.Windows.Visibility.Visible;
container.Opacity = 0.5;
this.container.Content = newBtn;
}
}
}
Mainpage.xaml:
<Grid xmlns:src="clr-namespace:LRDemo"
Background="White" Margin="10,0,-10,186" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<src:LoginInterfaceControl Grid.Row="0"/>
<!--<src:LoginInterfaceControl Grid.Row="1" Margin="0,15,0,0"/>-->
</Grid>
usercontrol.xaml
<ScrollViewer>
<ContentControl x:Name="container">
<StackPanel x:Name="Panel">
</StackPanel>
</ContentControl>
</ScrollViewer>
there is no need to again create stackpanel and contentcontrol in constructor of usercontrol because they are already there in usercontrol structure.
Contentcontrol can hold content that is assign to it last so I took stackpanel into contentcontol.
usercontrol.xaml.cs
public LoginInterfaceControl()
{
this.InitializeComponent();
abc();
}
public void abc()
{
for (int i = 0; i <= 5; i++)
{
Button newBtn = new Button()
{
Content = "name" + i,
Name = "name" + i,
Background = new SolidColorBrush(Colors.Black),
VerticalAlignment = VerticalAlignment.Center,
Opacity = 0.5
};
newBtn.Click += newBtn_Click;
container.Opacity = 0.5;
this.Panel.Children.Add(newBtn);
}
}
P.S : I do not know your exact need so I took static methods to add buttons.
My app crashes in the emulator when u load the map and then move the map and zoom in instantly. ive tried many different soulutions i found on the internet as the only error i get is Catastrophic Failure and no further information (no line number or any error information whatsoever)
C# code
public sealed partial class MapView : MvxWindowsPage
{
double lat=0;
double lon=0;
Geolocator gl = new Geolocator();
MapIcon Micon = new MapIcon();
Geopoint blo;
public MapView()
{
this.InitializeComponent();
Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;
GetInitialPosition();
}
private MapViewModel ViewModel
{
get { return DataContext as MapViewModel; }
}
private bool HasViewModel { get { return ViewModel != null; } }
void HardwareButtons_BackPressed(object sender, Windows.Phone.UI.Input.BackPressedEventArgs e)
{
e.Handled = true;
Windows.Phone.UI.Input.HardwareButtons.BackPressed -= HardwareButtons_BackPressed;
ViewModel.NavigateFirst();
}
async void GetInitialPosition()
{
gl.DesiredAccuracyInMeters = 500;
gl.DesiredAccuracy = PositionAccuracy.Default;
IAsyncOperation<Geoposition> locationTask = null;
try
{
Geoposition gp = await gl.GetGeopositionAsync(
maximumAge: TimeSpan.FromMinutes(5),
timeout: TimeSpan.FromSeconds(10)
);
//LatitudeTextBlock.Text = geoposition.Coordinate.Latitude.ToString("0.00");
//LongitudeTextBlock.Text = geoposition.Coordinate.Longitude.ToString("0.00");
}
finally
{
DispatcherTimer dt = new DispatcherTimer();
dt.Interval = new TimeSpan(0, 0, 5);
dt.Tick += (sender, e) => ProgBar.Visibility = Visibility.Collapsed;
dt.Tick += (sender, e) => ProgBar.IsEnabled = false;
dt.Start();
}
}
}
}
Xaml:
<views:MvxWindowsPage
xmlns:Maps="using:Windows.UI.Xaml.Controls.Maps"
x:Class="Etgarim.Views.MapView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Etgarim.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:views="using:Cirrious.MvvmCross.WindowsCommon.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Maps:MapControl x:Name="OmNaMap" MapServiceToken="..."/>
<!--Visibility="Visible" Center="{Binding blo}"-->
<ProgressBar x:Name="ProgBar" Height="667"/>
</Grid>
Move the map control and the progress bar so they not over lapping, this should resolve the issue.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="667"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<ProgressBar Grid.Row="0" x:Name="ProgBar" />
<Maps:MapControl Grid.Row="1" x:Name="OmNaMap" MapServiceToken="..."/>
<!--Visibility="Visible" Center="{Binding blo}"-->
</Grid>
I would like to show a ProgressBar when I call a method, so I have try to do this code:
if (parametro.chiave == "VIDEO")
{
//BISOGNA CARICARE IL VIDEO
String urlVideo=caricaVideoOnline(parametro.valore);
....
}
String caricaVideoOnline(string nomeFileVideo)
{
try
{
libreriaYouTube = new UploadVideo(ConfigurationManager.AppSettings["usernameYoutube"],
ConfigurationManager.AppSettings["passwordYouTube"],
ConfigurationManager.AppSettings["developmentKeyYouTube"],
ConfigurationManager.AppSettings["applicationNameYouTube"]);
libreriaYouTube.listaVideoToUpload.Add(nomeFileVideo);
// String video = libreriaYouTube.caricaVideo();
Thread t = new Thread(delegate()
{
for (int i = 0; i < 100000; i++)
{
if (i == 0)
{
ProgressBar progress = new ProgressBar();
progress.Show();
}
Console.WriteLine(i);
}
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
String video= libreriaYouTube.caricaVideo();
video = libreriaYouTube.caricaVideo();
return video;
}
catch (Exception e)
{
log.Error(e);
return null;
}
}
This code found but I show the ProgressBar but it is locked, I don't see the bar run.
This is a code of ProgressBar.xaml
<Window x:Class="Gestore.ProgressBar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Caricamento video" Height="100" Width="300"
>
<Grid Margin="20">
<ProgressBar Minimum="0" Maximum="100" Name="pbStatus" IsIndeterminate="True" Tag="Attendere....."/>
<Viewbox>
<TextBlock Text='Attendere ...' FontSize="2" x:Name="textVox"/>
</Viewbox>
</Grid>
</Window>
I see a couple of issues with your code:
You should access pbStatus, not create a new progress bar in code
You never update the value of your progress bar ("pbStatus.Value=...")
You can't update the progress bar from thread t. You need to invoke the application's UI thread to do this
The loop runs immediately through. Insert some sleep statements to control its timing behaviour.
The following sample code should work.
Xaml:
<StackPanel Orientation="Vertical">
<ProgressBar Name="pbStatus" Minimum="0" Maximum="100" Height="20"></ProgressBar>
<Button Click="ButtonBase_OnClick">Press me</Button>
</StackPanel>
Code behind:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
Thread t = new Thread(delegate()
{
for (int i = 0; i < 100; i++)
{
this.Dispatcher.Invoke(()=>
{
pbStatus.Value = i;
});
Thread.Sleep(500);
}
});
t.Start();
}