Navigation in C# and XAML - c#

I want to navigate to another page in my Windows Phone 8.1 app.I can easily do this if there is a button by clicking on it and using Frame.Navigate(typeof(MainPage)); in the event handler.But in my case I want to navigate to a second page automatically depending upon an integer value.If it becomes zero,the page automatically goes to second page.In my case I dont have a button and so event handler so to do this.How can I do this?

Implement the INotifyPropertyChanged interface for your view model. Here is a crude implementation, ideally, you would use an mvvm framework and send messages to your views as required.
View Model
public class GameStateViewModel : INotifyPropertyChanged
{
private int currentScore = 10;
/// <summary>
/// The timer here added to simulate whatever is supposed to be changing your value.
/// </summary>
public GameStateViewModel()
{
var timer = new DispatcherTimer
{
Interval = TimeSpan.FromSeconds(2)
};
timer.Tick += (sender, args) =>
{
if (this.CurrentScore > 0)
{
this.CurrentScore--;
}
else
{
timer.Stop();
}
};
timer.Start();
}
public event PropertyChangedEventHandler PropertyChanged;
public int CurrentScore
{
get { return currentScore; }
set
{
currentScore = value;
NotifyPropertyChanged("CurrentScore");
}
}
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Code behind
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
var viewModel = new GameStateViewModel();
viewModel.PropertyChanged += (sender, args) =>
{
if (viewModel.CurrentScore <= 0)
{
this.NavigationService.Navigate(new Uri("/Page2.xaml", UriKind.Relative));
}
};
this.DataContext = viewModel;
}
}
Xaml
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBlock Text="{Binding CurrentScore}" FontSize="{StaticResource PhoneFontSizeExtraLarge}" />
</Grid>

Related

Displaying random numbers with a DispatcherTimer

I've been looking for an answer but none seem to fit my question.
I am trying to adapt the MvVM method, but I dont think I fully understand it..
I'm trying to create an RPM display in WPF.
I want it to display an number (between 0-3000) and update this number every second (into a TextBlock).
I have created a new class where I try to create a DispatcherTimer and Random generator and then put that in the UI TextBlock.
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Threading;
namespace Aldeba.UI.WpfClient
{
public class GenerateRpm
{
public GenerateRpm()
{
DispatcherTimer timer = new DispatcherTimer
{
Interval = new TimeSpan(0, 0, 5)
};
timer.Start();
timer.Tick += Timer_Tick;
}
public int RandomValue()
{
Random random = new Random();
int RandomRpm = random.Next(0, 3001);
return RandomRpm;
}
void Timer_Tick(object sender, EventArgs e)
{
MainWindow mainWindow = new MainWindow();
GenerateRpm rpm = new GenerateRpm();
mainWindow.RpmDisplayLabel.Text = rpm.RandomValue().ToString();
}
}
}
My MainWindow.xaml.cs looks like...
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel();
this.DataContext = new GenerateRpm();
}
}
}
Do I need to add datacontext to all classes I want to access (for bindings for an example)?
This is the MainWindow where I want the Rpm displayed in the second TextBlock.
<StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Center">
<TextBlock Text="RPM:" Style="{StaticResource RpmDisplay}" />
<TextBlock x:Name="RpmDisplayLabel" Text="{Binding }" Style="{StaticResource RpmDisplay}" />
</StackPanel>
What am I missing and/ or doing wrong to be able to do this?
Use a view model like shown below, with a public property that is cyclically updated by the timer.
Make sure the property setter fires a change notification, e.g. the PropertyChanged event of the INotifyPropertyChanged interface.
public class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private readonly Random random = new Random();
public MainWindowViewModel()
{
var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
timer.Tick += Timer_Tick;
timer.Start();
}
private int randomRpm;
public int RandomRpm
{
get { return randomRpm; }
set
{
randomRpm = value;
PropertyChanged?.Invoke(
this, new PropertyChangedEventArgs(nameof(RandomRpm)));
}
}
private void Timer_Tick(object sender, EventArgs e)
{
RandomRpm = random.Next(0, 3001);
}
}
Assign an instance of the view model class to the MainWindow's DataContext:
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
In the view, bind an element to the view model property:
<TextBlock Text="{Binding RandomRpm}"/>

Write To Output message (C# => TextBox)

I have TextBox:
<TextBox DockPanel.Dock="Bottom"
FontFamily="Consolas"
Text="{Binding Path=Output}"
VerticalScrollBarVisibility="Visible"
HorizontalScrollBarVisibility="Auto"
AcceptsReturn="True"
AcceptsTab="True" />
To inside this TextBox I want to send some/add the message:
public string Output { get; set; }
public void WriteToOutput(string message)
{
Output += DateTime.Now.ToString("dd.MM HH:mm:ss") + " " + message + Environment.NewLine;
}
public void LoadExcelFile()
{
WriteToOutput("Start....")
//SOME CODE
WriteToOutput("End....")
}
Output should looks like:
Start...
End...
But the text it's not showing into TextBox. What is the reason?
Update: my MainViewModel.cs:
[AddINotifyPropertyChangedInterface]
public class MainViewModel
{
....
}
I'm using PropertyChanged.Fody
You're missing the INotifyPropertyChanged implementation.
A working example:
using System.ComponentModel;
public partial class MainWindow : Window, INotifyPropertyChanged
{
private string output;
public string Output
{
get { return output; }
set
{
output = value;
OnPropertyChanged(); // notify the GUI that something has changed
}
}
public MainWindow()
{
this.DataContext = this;
InitializeComponent();
this.Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Output = "Hallo";
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName: propertyName));
}
}
}
The XAML code would look like this:
<TextBox Text="{Binding Output}"/>
As you can see, whenever the Output property changes, the PropertyChanged event will be called. Every GUI Element that is bound to that Property will know that something has changed.
Note: [CallerMemberName] automatically gets the name of the property the method has been called with. If you don't want to use it, remove it. You'd have to change the OnPropertyChanged call to OnPropertyChanged("Output");, though.

Update ViewModel if Model changed

How can i update view model when model change. First solution that i found was subscribe in ViewModel for PropertyChangedEvent of Model. But is it good way? Maybe it exist better way to Notify ViewModel?
Xaml:
<Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="{Binding SomeValue}"/>
<Label Grid.Row="1" Content="{Binding Second}"/>
</Grid>
</Grid>
Code:
namespace WpfApplication
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
public class ViewModel : INotifyPropertyChanged
{
Model model = new Model();
public ViewModel()
{
model.PropertyChanged += (o, e) =>
{
PropertyChanged(this, new PropertyChangedEventArgs(e.PropertyName));
};
}
public int SomeValue
{
get
{
return this.model.SomeValue;
}
set
{
this.model.SomeValue = value;
}
}
public int Second
{
get
{
return this.model.Second;
}
set
{
this.model.Second = value;
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class Model : INotifyPropertyChanged
{
private int someValue;
public int SomeValue
{
get
{
return this.someValue;
}
set
{
this.someValue = value;
this.RaisePropertyChanged("SomeValue");
}
}
private int second;
public int Second
{
get
{
return this.second;
}
set
{
this.second = value;
this.RaisePropertyChanged("Second");
}
}
public Model()
{
Action Test = new Action(WorkAsync);
IAsyncResult result = Test.BeginInvoke(null,null);
}
public void WorkAsync()
{
while(true)
{
System.Threading.Thread.Sleep(3000);
SomeValue += 1;
Second += 1;
RaisePropertyChanged("SomeValue");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
}
Your model does not necessarily need to implement INotifyPropertyChanged, a pure MVVM approach would be to implement INotifyPropertyChanged in the View Model and expose only properties of which the view requires of the Model.
In your case, it'll look like this:
public class Model
{
public int SomeValue { get; set; }
}
public ViewModel : INotifyPropertyChanged
{
private Model _model = new Model();
public int SomeModelValue
{
get { return _model.SomeValue; }
set
{
_model.SomeValue = value;
//Notify property changed
}
}
...
}
And your view will bind to SomeModelValue:
<TextBox Text="{Binding SomeModelValue}" ... />
The benefit of this approach is that your view model is not exposing the entire model to the view, and only properties of the model that need to be exposed will be seen by the view. It also allows your model to remain relatively dumb.
create a raisepropertychanged method/call it
enforce two way binding on the control
look here
and here
and here is best
xaml two way binding

WPF, Property does not return value to the binding

So, I have a project with a scrolling text (marqee) that rotates over a string array. And I want it to change the string value after 20 seconds of each animation iteration.
There is a problem though, the property(ScrollingText) that uses the INotifyPropertyChanged interface to bind to a textblock(using XAML) does not return after the first iteration. Even though it refreshes normally(in the set part), it does not return on the Getter part.... except for the first set in the default ctor.
MAIN CLASS:
class GetScrollingText : CommonBase
{
private string _scrollingtext = String.Empty;
DoubleAnimation Animation;
public GetScrollingText()
{
ScrollingText = GetScrollString();
}
public string ScrollingText
{
get
{
return _scrollingtext;
}
set
{
if (value != _scrollingtext)
{
_scrollingtext = value;
RaisePropertyChanged("ScrollingText");
}
}
} // INJECTS the string in the animated textblock {binding}.
public TextBlock scrollBlock { get; set; }
string GetScrollString()
{
.........
return scrolltext;
}
public void LeftToRightMarqee(double from, double to)
{
Animation = new DoubleAnimation();
Animation.From = from;
Animation.To = to;
Animation.Duration = new Duration(TimeSpan.FromSeconds(20));
Animation.Completed += animation_Completed;
scrollBlock.BeginAnimation(Canvas.LeftProperty, Animation);
}
void animation_Completed(object sender, EventArgs e)
{
ScrollingText = GetScrollString();
scrollBlock.BeginAnimation(Canvas.LeftProperty, Animation);
}
}
For some reason the animation_Completed Event only changes the value ScrollingText, but it does not invoke the Getter part therefore there is not a return to the {binding}.
XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:AnnouncingSys"
x:Class="AnnouncingSys.MainWindow"
x:Name="Window"
Width="1280" Height="720" MinHeight="566" MinWidth="710">
<Window.Resources>
<vm:GetScrollingText x:Key="ScrollingText"/>
</Window.Resources>
<Canvas x:Name="MainCanvas" ClipToBounds="True" Margin="0,0,0,0" Grid.Row="5" Background="Black" Grid.ColumnSpan="5" >
<TextBlock x:Name="ScrollBlock" TextWrapping="Wrap" VerticalAlignment="Top" Height="113" Width="5147" Canvas.Left="-1922" Text="{Binding ScrollingText, Source={StaticResource ScrollingText}}"/>
</Canvas>
</Window>
CODE BEHIND:
public partial class MainWindow : Window
{
GetScrollingText scrolling = new GetScrollingText();
public MainWindow()
{
InitializeComponent();
scrolling.scrollBlock = this.ScrollBlock;
scrolling.LeftToRightMarqee(2000, -3000);
}
}
And finally the helper class CommonBase:
public class CommonBase : INotifyPropertyChanged
{
protected CommonBase()
{
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string PropertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
PropertyChangedEventArgs e = new PropertyChangedEventArgs(PropertyName);
handler(this, e);
}
}
}
I have even put a breakpoint on the return block of the Getter but it only activates on the first: "ScrollingText = GetScrollString()". I mean, shouldn't it return each time the value is changed???
You are using two different instances of your GetScrollingText class, one in XAML as StaticResource, the other in code behind as the scrolling field in class MainWindow.
Instead of creating a StaticResource in XAML, you could just set the DataContext property of your MainWindow:
public partial class MainWindow : Window
{
GetScrollingText scrolling = new GetScrollingText();
public MainWindow()
{
InitializeComponent();
scrolling.scrollBlock = this.ScrollBlock;
scrolling.LeftToRightMarqee(2000, -3000);
DataContext = scrolling; // here
}
}
Now you would not explicitly set the binding's Source property, because the DataContext is used as default binding source:
<TextBlock ... Text="{Binding ScrollingText}"/>

WPF UserControl property change not updating

I have a UserControl that I add to my main application.
That UserControl contains a button for a UIElement
The UserControl contains a DispatchTimer and every 2 seconds based on some int values determines what the button image will be.
One of the methods called in the UserControl should set it's image but the control never displays the image that it was changed to.
public void SetNormal()
{
btnFlashAlert.Content = new BitmapImage(new Uri("Images/FlashButton.png", UriKind.RelativeOrAbsolute));
}
Is there something i'm missing to get the look of the control update on the main application?
When I look at what .Content contains, it is correct. The UI doesn't reflect the change.
XAML
<UserControl x:Class="SC.FlashSystem.MainButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" Height="53" Width="164">
<Button x:Name="btnFlashAlert" Background="{x:Null}" BorderBrush="{x:Null}" Cursor="Hand" Click="btnFlashAlert_Click">
<Button.Template>
<ControlTemplate>
<Image Source="Images/FlashButton.png"/>
</ControlTemplate>
</Button.Template>
</Button>
Codebehind Updated
public partial class MainButton : UserControl
{
private SupportConsoleWeb.MessageData messageCounts { get; set; }
private readonly DispatcherTimer flashButtonChangeTimer = new DispatcherTimer();
private BitmapImage NormalImage { get; set; }
private BitmapImage CriticalImage { get; set; }
private BitmapImage AlertImage { get; set; }
private BitmapImage InfoImage { get; set; }
public MainButton()
{
InitializeComponent();
messageCounts = new SupportConsoleWeb.MessageData();
messageCounts.CriticalCount = 0;
messageCounts.AlertCount = 0;
messageCounts.InfoCount = 0;
NormalImage = new BitmapImage(new Uri("Images/FlashButton.png", UriKind.RelativeOrAbsolute));
CriticalImage = new BitmapImage(new Uri("Images/FlashButtonRed.png", UriKind.RelativeOrAbsolute));
AlertImage = new BitmapImage(new Uri("Images/FlashButtonOrange.png", UriKind.RelativeOrAbsolute));
InfoImage = new BitmapImage(new Uri("Images/FlashButtonGreen.png", UriKind.RelativeOrAbsolute));
flashButtonChangeTimer.Interval = TimeSpan.FromSeconds(2);
flashButtonChangeTimer.Tick += flashButtonChangeTimer_Tick;
flashButtonChangeTimer.Start();
}
void flashButtonChangeTimer_Tick(object sender, EventArgs e)
{
btnFlashAlert.Dispatcher.BeginInvoke(new Action(() =>
{
if (btnFlashAlert.Content == null)
{
SetNormal();
}
else if (messageCounts.CriticalCount > 0 && btnFlashAlert.Content.Equals(CriticalImage))
{
SetNormal();
}
else if (messageCounts.AlertCount > 0 && btnFlashAlert.Content.Equals(AlertImage))
{
SetNormal();
}
else if (messageCounts.InfoCount > 0 && btnFlashAlert.Content.Equals(InfoImage))
{
SetNormal();
}
else if (messageCounts.CriticalCount > 0)
{
SetCritical();
}
else if (messageCounts.AlertCount > 0)
{
SetAlert();
}
else if (messageCounts.InfoCount > 0)
{
SetInfo();
}
}));
}
public void UpdateMessageCounts(SupportConsoleWeb.MessageData messageCounts)
{
this.messageCounts = messageCounts;
}
private void btnFlashAlert_Click(object sender, RoutedEventArgs e)
{
MainWindow window = new MainWindow();
window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
window.ShowDialog();
}
public void SetMessageCount(int criticalCount, int alertCount, int infoCount)
{
messageCounts.CriticalCount = criticalCount;
messageCounts.AlertCount = alertCount;
messageCounts.InfoCount = infoCount;
}
private void SetNormal()
{
btnFlashAlert.Content = NormalImage;
}
private void SetCritical()
{
btnFlashAlert.Content = CriticalImage;
}
private void SetAlert()
{
btnFlashAlert.Content = AlertImage;
}
private void SetInfo()
{
btnFlashAlert.Content = InfoImage;
}
}
Change your XAML To this
<Image Source="{Binding TheImage}"/>
Add notify property changed
public partial class MainButton : UserControl, INotifyPropertyChanged
Create the OnPropertyChanged Event
void OnPropertyChanged(String prop)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
public event PropertyChangedEventHandler PropertyChanged;
Create a Bitmap prop and notify the prop changed event
private BitmapImage _TheImage;
public BitmapImage TheImage
{
get { return _TheImage; }
set { _TheImage = value; OnPropertyChanged("TheImage"); }
}
In your initializer
public MainButton()
{
this.DataContext = this;
InitializeComponent();
TheImage = new BitmapImage();
Now in your setting methods call
TheImage = //Your Bitmap Goes here
I know this seems excessive but you will see it is a much cleaner implementation in the long run.
I believe its an issue with picture selection logic not having a default image when none of the conditions are met...
With that said, IMHO the picture logic would be better expressed by having all images pre-loaded and their visibility initially set to hidden. Then bind the visibility of each image to a specific flag boolean on the VM. Which the timer event can simply turn on or off the boolean(s) which will ultimately show or hide images as needed.
That removes any latency due to loading and showing of images for they will be pre-loaded; also it will solve any possible future memory issues due to loading/unloading of images.
Example
The following example has a button with two images. Both image's visibility is bound to Booleans on the VM. The VM has one Boolean which the imageas work off of and a timer which changes its status every two seconds switching the images.
Xaml:
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>
<Button x:Name="bStatus" Width="48" Height="48">
<StackPanel Orientation="Vertical">
<Image Source="Images\Copy-icon.png" Visibility="{Binding IsCopyOn,
Converter={StaticResource BooleanToVisibilityConverter}}" />
<Image Source="Images\Recycle-icon.png"
Visibility="{Binding IsRecycleOn,
Converter={StaticResource BooleanToVisibilityConverter}}" />
</StackPanel>
</Button>
VM
public class MainVM : INotifyPropertyChanged
{
private bool _bSwitch;
private readonly DispatcherTimer flashButtonChangeTimer = new DispatcherTimer();
public bool IsRecycleOn
{
get { return _bSwitch; }
}
public bool IsCopyOn
{
get { return !_bSwitch; }
}
public MainVM()
{
flashButtonChangeTimer.Interval = TimeSpan.FromSeconds(2);
flashButtonChangeTimer.Tick += (sender, args) =>
{
_bSwitch = ! _bSwitch;
OnPropertyChanged("IsCopyOn");
OnPropertyChanged("IsRecycleOn");
};
flashButtonChangeTimer.Start();
}
/// <summary>Event raised when a property changes.</summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>Raises the PropertyChanged event.</summary>
/// <param name="propertyName">The name of the property that has changed.</param>
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Categories