I have a webbrowser that uses a simple forward and backward navigation scheme, and may also refresh or stop navigation if the user so choses. All navigation is working correctly, but my issue arises when I try to toggle the 'refresh' and 'stop' buttons depending on whether the webbrowser is Navigating or has Navigated. I would like for the refresh button to be set to visible as long as no navigation is occuring, and for the stop button to be set to visible while navigation is occuring. My basic implementation is as follows but I cannot seem to get the buttons to toggle from Visible to Collapsed depending on these scenarios.
MainPage.xaml
<Button x:Name="RefreshButton" Content="" Style="{StaticResource RefreshBtn}" Grid.Column="0" Grid.Row="0" Visibility="Visible" Click="RefreshButton_Click" toolkit:TiltEffect.IsTiltEnabled="True">
<Button x:Name="StopButton" Content="" Style="{StaticResource StopBtn}" Grid.Column="0" Grid.Row="0" Visibility="Collapsed" Click="StopButton_Click" toolkit:TiltEffect.IsTiltEnabled="True"/>
MainPage.xaml.cs
public MainPage()
{
InitializeComponent();
//Change Navigation buttons if the browser is currently Navigating
if (TheBrowser._IsNavigating == false)
{
RefreshButton.Visibility = Visibility.Visible;
StopButton.Visibility = Visibility.Collapsed;
}
else
{
RefreshButton.Visibility = Visibility.Collapsed;
StopButton.Visibility = Visibility.Visible;
}
//while (TheBrowser._IsNavigating == true)
//{
// RefreshButton.Visibility = Visibility.Collapsed;
// StopButton.Visibility = Visibility.Visible;
//}
}
WebBrowser.xaml.cs
//Flag to check if the browser is navigating
public bool _IsNavigating = false;
void TheWebBrowser_Navigating(object sender,
Microsoft.Phone.Controls.NavigatingEventArgs e)
{
_IsNavigating = true;
}
void TheWebBrowser_Navigated(object sender,
System.Windows.Navigation.NavigationEventArgs e)
{
_IsNavigating = false;
}
My WebBrowser.xaml.cs is a webbrowser user control which is embedded into MainPage.xaml and named TheBrowser. When debugging, I can see the changes in the bool variable _IsNavigating between true and false as shown above but this change is not detected in MainPage.xaml.cs which is why I think the button visibility does not change. Any help with this issue would be greatly appreciated.. I have run out of ideas of how to fix this! Thanks in advance.
The code for setting the visibility is in the wrong place, right now it is only called upon page construction.
You have to call the code whenever your _isNavigating variable changes.
Do the following:
void ChangeVisibility()
{
if (TheBrowser._IsNavigating == false)
{
RefreshButton.Visibility = Visibility.Visible;
StopButton.Visibility = Visibility.Collapsed;
}
else
{
RefreshButton.Visibility = Visibility.Collapsed;
StopButton.Visibility = Visibility.Visible;
}
}
void TheWebBrowser_Navigating(object sender,
Microsoft.Phone.Controls.NavigatingEventArgs e)
{
_IsNavigating = true;
ChangeVisibility();
}
void TheWebBrowser_Navigated(object sender,
System.Windows.Navigation.NavigationEventArgs e)
{
_IsNavigating = false;
ChangeVisibility();
}
Related
I got this layout:
<RelativePanel>
<ButtonContent="" Name="btHumburger"/>
<Button Content="" Name="btBack"/>
<TextBlock Text="Home" Name="tbHeader"/>
<Button Content="" Name="btSearch"/>
<SearchBox Visibility="Collapsed" Name="asbSearch" LostFocus="asbSearch_LostFocus"/>
</RelativePanel>
And i want to display SearchBox only when i hit button btSearch, and hide it when focus is lost. In codebehind:
private void btSearch_Click(object sender, RoutedEventArgs e)
{
asbSearch.Visibility = Visibility.Visible;
asbSearch.Focus(FocusState.Programmatic);
btHumburger.Visibility = Visibility.Collapsed;
btBack.Visibility = Visibility.Collapsed;
tbHeader.Visibility = Visibility.Collapsed;
btSearch.Visibility = Visibility.Collapsed;
}
private void asbSearch_LostFocus(object sender, RoutedEventArgs e)
{
asbSearch.Visibility = Visibility.Collapsed;
btHumburger.Visibility = Visibility.Visible;
btBack.Visibility = mainFrame.CanGoBack ? Visibility.Visible : Visibility.Collapsed;
tbHeader.Visibility = Visibility.Visible;
btSearch.Visibility = Visibility.Visible;
}
But asbSearch dont get focused/placed caret after asbSearch.Focus(FocusState.Programmatic);, so LostFocus event wont fire. How to handle this?
Try calling asbSearch.UpdateLayout(); before setting the focus.
It seems that the Visibility change is not fully finished and the control can't receive focus before that.
Trying to have a default value for my radio buttons, but get flagged an NullReferenceException error.
private void rbImperial_Checked(object sender, RoutedEventArgs e)
{
txtInches.Visibility = Visibility.Visible;
lblInches.Visibility = Visibility.Visible;
lblWeight.Text = "lbs";
lblHeight.Text = "Feet";
}
private void rbMetric_Checked(object sender, RoutedEventArgs e)
{
lblHeight.Text = "cm";
txtInches.Visibility = Visibility.Collapsed;
lblInches.Visibility = Visibility.Collapsed;
lblWeight.Text = "kg";
}
rbImperial is the defaulted radio button that should be checked.
XAML:
<RadioButton x:Name="rbMetric" Content="Metric" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="132,244,0,0" Checked="rbMetric_Checked" ClickMode="Press"/>
<RadioButton x:Name="rbImperial" Content="Imperial" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="132,199,0,0" Checked="rbImperial_Checked" IsChecked="True" ClickMode="Press" />
If I don't have the rbImperial Checked property to be True to make it defaulted to be selected it runs perfectly fine.
What am I missing?
My issue when I try to run it.
Try setting the default value in the constructor. Not the prettiest method, but it should work. Alternatively, you can bind it to the ViewModel; that should work as well.
i have been read some similar questions on Stackoverflow but cannot make it works correctly
Here is my WebBrowser XAML code
<phone:WebBrowser Name="webBrowser"
ScriptNotify="webBrowser_ScriptNotify"
IsScriptEnabled="True"
Margin="0"
Background="Transparent"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
and Application Bar in code
void BuildAppBar()
{
ApplicationBar = new ApplicationBar();
ApplicationBar.Mode = ApplicationBarMode.Minimized;
...
}
This happens when you have set the Mode Property of ApplicationBar to Minimized (i don't know why), so what you can do is to use OrientationChanged event of the page to set the Mode Property:
private void PhoneApplicationPage_OrientationChanged(object sender, OrientationChangedEventArgs e)
{
if (e.Orientation == PageOrientation.PortraitUp)
{
this.ApplicationBar.Mode = ApplicationBarMode.Minimized;
}
else
{
this.ApplicationBar.Mode = ApplicationBarMode.Default;
}
}
Background:
I have a usercontrol defined in a ScrollViewer along with a ContentControl, the ContentControl will be visible all the time, and within it there is a Button, when the button is clicked will set the usercontrol to Visible, and when the usercontrol shows (Visiblility="Visible") I want it to be scrolled into the view. I have
XAML
<ScrollViewer VerticalScrollBarVisibility="Auto" MaxHeight="465">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ContentControl Content="{Binding MyOtherViewModel}" Width="960" ></ContentControl>
<local:MyView IsVisibleChanged="MyView_IsVisibleChanged" Grid.Row="1" Visibility="{Binding IsNonCompliant, Converter={StaticResource BooltoVisible}, UpdateSourceTrigger=PropertyChanged}" />
</ScrollViewer>
Code Behind
private void MyView_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
(sender as Control).BringIntoView();
}
Problem: this is not working, or more precisely, my usercontrol scrolled into the view first then revert back to the bottom of the ScrollViewer in a blink.
Weird thing: show a messagebox before calling BringIntoView will correctly display my usercontrol into the middle of the view
Current hack solution: you can see this works even to close the Window immediately after its loaded
private void MyView_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
Window ss = new Window();
ss.Loaded += new RoutedEventHandler(ss_Loaded);
ss.ShowDialog();
(sender as Control).BringIntoView();
}
private void ss_Loaded(object sender, RoutedEventArgs e)
{
(sender as Window).Close();
}
Question: I know there must be something else going on, but I just can't identify it, but I really want to know what happened when a window showing with ShowDialog? Is this because it refreshes the window so that the BringIntoView will happen only after the usercontrol been loaded? (Not as the problem I have now: BringIntoView happened first, and then the window get refreshed and put the scrollbar back to the top). And what is the correct fix for my problem?
It looks like BringIntoView called before my Usercontrol getting rendered, as a result when it gets fully rendered, the scrollbar is revert back to the top (as I have described in my question). And thanks for the answer from #Evgeny posted for another question, I get a better solution now (less hack maybe?). Still want to see if there are better solutions.
private void MyView_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var border = (FrameworkElement)sender;
if (border.IsVisible)
{
//Window ss = new Window();
//ss.Loaded += new RoutedEventHandler(ss_Loaded);
//ss.ShowDialog();
using (BackgroundWorker bg = new BackgroundWorker())
{
bg.DoWork += new DoWorkEventHandler(bg_DoWork);
bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_RunWorkerCompleted);
Tuple<FrameworkElement, double> b = new Tuple<FrameworkElement, double>(border, border.Height);
bg.RunWorkerAsync(b);
}
}
}
private void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
(e.Result as UserControl).BringIntoView();
}
private void bg_DoWork(object sender, DoWorkEventArgs e)
{
int maxwait = 300 //not scrolled to the view is not a disaster, but if the program hangs forever it will be a disaster, so set this to prevent that from happening
while (maxwait!=0
&&
(e.Argument as Tuple<FrameworkElement, double>).Item1.ActualHeight != (e.Argument as Tuple<FrameworkElement, double>).Item2)
{
Thread.Sleep(1);
maxwait --;
}
e.Result = (e.Argument as Tuple<FrameworkElement, double>).Item1;
}
I cannot believe that using background worker is a correct solution for this! You can use LayoutUpdated event to easily find when control is loaded and finally displayed.
userControl.LayoutUpdated+=OnLayoutUpdated;
private bool loaded=false;
private void OnLayoutUpdated(object sender,EventArgs e)
{
if (!loaded && (view.ActualHeight > 0 || view.ActualWidth > 0))
{
// Unsubscribe or set a flag.
userControl.LayoutUpdated -= OnLayoutUpdated;
loaded = true;
}
}
So you can execute that code when layout is updated and height or width is set. This will means that control is loaded and displayed.
Than you can unsubscribe or set a flag that initialization is complated.
I hope you can help me to solve my problem. I have a simple metro app. A textblock named myTextBlock is placed in the HomePageView page. This is its xaml:
<TextBlock x:Name="myTextBlock" Text="Hello" HorizontalAlignment="Center" VerticalAlignment="Top" Style="{StaticResource timeStyle}" TextAlignment="Center" FontSize="300" RenderTransformOrigin="0.5,0.5" Margin="11,55,3,0" ManipulationMode="All">
This is the LoadState in the HomePageView code behind:
protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
try
{
double? myTextBlockValue = (double?)ApplicationData.Current.LocalSettings.Values["myTextBlockSize"];
if (myTextBlockValue != null)
{
myTextBlock.FontSize = (double)myTextBlockValue;
}
}
catch
{
}
}
I built a Settings pane (charm bar -> settings -> settings) named SettingsPage in which a slider named timeSlider is placed. This is its xaml:
<Slider x:Name="timeSlider" Width="257" Minimum="1" Maximum="600" Loaded="timeSlider_Loaded" ValueChanged="timeSlider_ValueChanged" />
And these are the slider Loaded and ValueChanged methods placed in the SettingsPage codebehind:
private void timeSlider_Loaded(object sender, RoutedEventArgs e)
{
var sliderIstance = sender as Slider;
double? storedSize = (double?)ApplicationData.Current.LocalSettings.Values["myTextBlockSize"];
if (storedSize != null && storedSize != 1)
sliderIstance.Value = (double)storedSize;
else
sliderIstance.Value = 300;
}
private void timeSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
var sliderIstance = sender as Slider;
ApplicationData.Current.LocalSettings.Values["myTextBlockSize"] = sliderIstance.Value as double?;
var _Frame = Window.Current.Content as Frame;
_Frame.Navigate(_Frame.Content.GetType());
_Frame.GoBack();
}
You can download the complete solution here on my skydrive: https://skydrive.live.com/redir?resid=1B721133DC03E67C!7350
In this way, I linked the fontsize property of myTextBlock (in the HomePageView page) to the value property of the slider (in the SettingsPage page), so the user can change this property at runtime. Also, this property is stored in the myTextBlockSize ApplicationData variable to preserve its value when the app is closed and reopened.
The solution works but THE PROBLEM is: when I enter the settings pane (charm bar -> settings -> settings) and change the textblock fontsize property through the slider, then I come back to the homepageview and reopen the settings pane, the fontsize property is reinitialized to its original value so it doesn't keep the previous (user selected) value.
Can you fix my code please? Thank you very much in advance.
You have to add one condition if (sliderIstance.Value != 1) in timeSlider_ValueChanged event
private void timeSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
var sliderIstance = sender as Slider;
if (sliderIstance.Value != 1)
ApplicationData.Current.LocalSettings.Values["myTextBlockSize"] = sliderIstance.Value as double?;
var _Frame = Window.Current.Content as Frame;
_Frame.Navigate(_Frame.Content.GetType());
_Frame.GoBack();
}