Activation before proper Deactivation WP7 - silverlight

In my app I allow the user to go to the marketplace for various reasons. While loading the marketplace, if the user hits the back button very quickly it will try to go back to my apps saved stated. All my data from iso-storage etc is loaded just fine, but the screen is frozen. I have different application bars for various pivot items and as I do the swiping motion, I see the application bar changing, so I know the app is responsive.
The main problem is that the screen is stuck where the user initially launched the marketplace task. I understand that int this edge case, my App and Page constructors are not firing, and the events that are firing are on navigated from, application deactivated, application activated, and on navigated to.
I thought I could use a Boolean to basically cover the case for when a marketplace task has fired so that way I can reload the data context in the on navigated to method and set it to my view model. The screen however is still frozen.
Any help on this issue is greatly appreciated,
Thanks
Edit: Here is some relevant code
private void Application_Activated(object sender, ActivatedEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
}
DetermineIsTrial();
}
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
if (playerController.chapterPlayer != null)
{
var store = new PersistentDataStorage();
store.Backup(StringResource.ChapterPosition, playerController.chapterPlayer.Position);
store.Backup(StringResource.ChapterUriString, playerController.chapterPlayer.Source.OriginalString);
store.Backup(StringResource.NaturalDuration, playerController.chapterPlayer.NaturalDuration.TimeSpan);
}
}
Main Page XAML:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
App.viewIdentifier = StringResource.MainPageView;
if (App.firstTimeLoading == false && PivotBackground.SelectedItem != SuggestedPivotItem)
{
BuildApplicationBar();
}
else if (PivotBackground.SelectedItem == SuggestedPivotItem)
{
BuildMarketPlaceApplicationBar();
}
if (App.firstTimeLoading == true)
{
BuildApplicationBar(); //builds the application bar
//Restore the state from tombstone and set the audioplayer.
App.playerController = new PlayerButtonsController();
App.playerController.SetMediaPlayer(App.MainAudioPlayer);
RestoreState();
ResourceDictionary appResourceList = App.Current.Resources;
App.firstTimeLoading = false;
//default source for chapter position
App.AudioMgr.SetChapterSource(0);
}
}
More methods:
private void RestoreState()
{
var store = new PersistentDataStorage();
playerWasWhere = store.Restore<TimeSpan>(StringResource.ChapterPosition);
naturalDuration = store.Restore<TimeSpan>(StringResource.NaturalDuration);
currentAudioFile = store.Restore<String>(StringResource.ChapterUriString);
SetAudioListScrollPosition();
App.playerController.SetPositionFromIsoStorage(currentAudioFile, playerWasWhere, naturalDuration);
}
public void LoadData()
{
CreateAudioPlayerGUIfromChapterList();
CreateAboutMenuGUIfromExtrasData();
CreateQuotesMenuGUIfromExtrasData();
this.IsDataLoaded = true;
}
private void CreateAudioPlayerGUIfromChapterList()
{
int numberOfChapters = 0;
for (int i = 0; i < App.AudioMgr.Parts.Count; i++)
{
ObservableCollection<ItemViewModel> tempObservableCollection = new ObservableCollection<ItemViewModel>();
for (int j = 0; j < App.AudioMgr.Parts[i].NumberOfChapters; j++)
{
tempObservableCollection.Add(new ItemViewModel()
{
LineOne = ProcessTitle(App.AudioMgr.Chapters[numberOfChapters + j].Title),
LineTwo = App.AudioMgr.Chapters[numberOfChapters + j].StatusMessage,
ItemAlpha = 0.0,
ChapterForeground = ChapterInfo.StatusColor[(int)App.AudioMgr.Chapters[numberOfChapters + j].Status],
Progress = 0,
Width = 0,
UserColorTheme = App.accentBrush,
PlayIconVisible = Visibility.Collapsed,
ChapterDurationProgressBarAdjacent = StringResource.Space,
ContainingPart = i,
MediaStateImageSource = StringResource.KJIcons + App.themeDir + StringResource.AppBarSpeaker
});
}
numberOfChapters += App.AudioMgr.Parts[i].NumberOfChapters;
//no parts header doesn't need spacing or border since its the first header.
if (i == 0 && App.AudioMgr.Parts[i].Title == "")
{
Parts.Add(new PartsViewModel()
{
PartsHeader = StringResource.Space,
ChapterForeground = App.defaultForeground,
ChaptersInPart = tempObservableCollection,
PartsBackgroundBrush = App.partsBackgroundBrush,
PartsHeaderHeight = 0,
PartsBorderThickness = new Thickness(0)
});
}
//parts header needs spacing and border
else if (App.AudioMgr.Parts[i].Title != "")
{
Parts.Add(new PartsViewModel()
{
PartsHeader = App.AudioMgr.Parts[i].Title,
ChapterForeground = App.defaultForeground,
ChaptersInPart = tempObservableCollection,
PartsBackgroundBrush = App.partsBackgroundBrush,
PartsHeaderHeight = double.NaN,
PartsBorderThickness = new Thickness(0,0,0,2)
});
}
else
{
Parts.Add(new PartsViewModel()
{
PartsHeader = StringResource.Space,
ChapterForeground = App.defaultForeground,
ChaptersInPart = tempObservableCollection,
PartsBackgroundBrush = App.partsBackgroundBrush,
PartsHeaderHeight = 0,
PartsBorderThickness = new Thickness(0)
});
}
}
}
private void CreateAboutMenuGUIfromExtrasData()
{
int list_count = 0;
for (int i = 0; i < 3; ++i)
{
switch (i)
{
//Evaluate number of Authors
case 0:
list_count = DictionaryIterator(App.Parser.AboutAuthorsArrayList);
if (list_count == 1)
{
this.About.Add(new ItemViewModel() { LineOne = StringResource.AboutAuthor }); //for one author
}
else if (list_count > 1)
{
this.About.Add(new ItemViewModel() { LineOne = StringResource.AboutAuthors }); //for more than one author
}
break;
//Evaluate number of books (should only be one)
case 1:
list_count = DictionaryIterator(App.Parser.AboutBookArrayList);
if (list_count > 0)
this.About.Add(new ItemViewModel() { LineOne = StringResource.AboutBook });
break;
//Evaluate number of Readers
case 2:
list_count = DictionaryIterator(App.Parser.AboutNarratorsArrayList);
if (list_count == 1)
{
this.About.Add(new ItemViewModel() { LineOne = StringResource.AboutReader }); //for one reader
}
else if (list_count > 1)
{
this.About.Add(new ItemViewModel() { LineOne = StringResource.AboutReaders}); //for more than one reader
}
break;
}
}
}
private void CreateQuotesMenuGUIfromExtrasData()
{
int list_count = 0;
for( int i = 0; i < 6; ++i )
{
switch( i )
{
case 0:
list_count = DictionaryIterator(App.Parser.QuotesAuthorAboutArrayList);
if (list_count == 1)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesAboutAuthor});
else if(list_count > 1)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesAboutAuthors });
break;
case 1:
list_count = DictionaryIterator(App.Parser.QuotesAuthorFromArrayList);
if (list_count == 1)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesFromAuthor });
else if (list_count > 1)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesFromAuthors});
break;
case 2:
list_count = DictionaryIterator(App.Parser.QuotesBookAboutArrayList);
if (list_count > 0)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesAboutBook });
break;
case 3:
list_count = DictionaryIterator(App.Parser.QuotesBookFromArrayList);
if (list_count > 0)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesFromBook });
break;
case 4:
list_count = DictionaryIterator(App.Parser.QuotesReaderAboutArrayList);
if (list_count == 1)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesAboutReader });
else if (list_count > 1)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesAboutReaders });
break;
case 5:
list_count = DictionaryIterator(App.Parser.QuotesReaderFromArrayList);
if (list_count == 1)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesFromReader });
else if (list_count > 1)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesFromReaders });
break;
}
}
}

Basically this happens because your code is locking up the UI thread. And the reason it locks it up, is because it's way to slow.
And looking at your code now, it's a crazy amount of work you're doing in what should be a simple data loading from the isolated storage. You need to move all this UI work over to the View, and first handle it upon creation of the actual view, not before, as you're doing right now.
Personally I dislike the idea of coupling the viewmodel with your App class, and I also think it's pointless to use the Application_Activated/Deactivated for tombstoning, rather than handling persistence at OnNavigatedFrom and OnNavigatedTo.
I think it'll be difficult to give a precise answer to what is causing the problem, but my guess right now lies in that you're using the process for the tombstoning to re-create the UI, instead of letting the UIThread itself do the work.
The whole part about you're generating the UI in C# is just so plain wrong as it can be. XAML is made for this, and it's really good at what it's made for.

Are you sure that you're only restoring state if the code was actually tombstoned?
I suspect that you're coming back to your app before it is tombstoned but still trying to restore state. Quite what you're saving and how you restore it will determine how you can check if you need to restore it. Checking for null or if not the defautl value is probably the easiest way.
You may also get better performance if you only save the state of anything you absolutely have to. You should also try saving the State in the OnNavigatingFrom event, rather than the OnNavigatedFrom event.
What and how are you saving to IS?
Why not use the Page.State object?

Related

WPF list modification during iteration?

I'm trying to make a very simple game where the yellow ball bouncing back and fourth. If it collides with one of the moving blue squares, the square is supposed to disappear and a new one should appear (always 3 in the window) elsewhere. When my code reaches this part, all 3 squares disappear (then reappears as intended it is not a problem) and I just cant figure out why. It would be a huge help if somebody could run over my methods responsible for the problem. Thank you in advance.
So my timer_Tick method, responsible for every frame:
void timer_Tick(object sender, EventArgs e)
{
logic.MoveBall();
if (model.Enemy.Count<3)
{
logic.AddEnemy();
}
int iii = 0;
foreach (MyShape enemy in model.Enemy) //the whole thing from here is me trying to solve list modification during iteration
{
if (logic.MoveEnemy(enemy) == -1)
{
logic.MoveEnemy(enemy);
}
else iii = logic.MoveEnemy(enemy);
}
if (iii > -1)
{
for (int j = model.Enemy.Count - 1; j >= 0; j--)
{
if (j == model.Enemy.Count - iii)
{
model.Enemy.RemoveAt(j);
}
}
}
}
MoveEnemy: I try to decide whether there is collusion and if yes, then try to remove the given shape object (blue square). Because This whole method is in a foreach, I just save the removable element and forward it to timer_Tick
public int MoveEnemy(MyShape shape)
{
int i = 0;
int ii = -1;
if ((shape.Area.IntersectsWith(model.Ball.Area)))
{
i = 0;
foreach (var e in model.Enemy)
{
i++;
if (shape == e)
{
ii = i;
}
}
}
shape.ChangeX(shape.Dx);
shape.ChangeY(shape.Dy);
bool coll = false;
foreach (var e in model.Enemy)
{
if ((e.Area.IntersectsWith(shape.Area)) && (shape != e))
{
coll = true;
}
}
if (shape.Area.Left < 0 || shape.Area.Right > Config.Width-40 || coll)
{
shape.Dx = -shape.Dx;
}
if (shape.Area.Top < 0)
{
shape.Dy = -shape.Dy;
}
if (shape.Area.Bottom > Config.Height/2)
{
shape.Dy = -shape.Dy;
}
RefreshScreen?.Invoke(this, EventArgs.Empty);
return ii;
}
And finally AddEnemy:
public void AddEnemy()
{
rnd = new Random();
int r = rnd.Next(-300, 300);
model.Enemy.Add(new MyShape(Config.Width / 2+r, 0, 40, 40));
RefreshScreen?.Invoke(this, EventArgs.Empty);
}
List<T> (or IList and Enumerable) exposes some useful methods to compact code:
int itemIndex = list.IndexOf(item); // Gets the index of the item if found, otherwise returns -1
list.Remove(item); // Remove item if contained in collection
list.RemoveAll(item => item > 5); // Removes all items that satisfy a condition (replaces explicit iteration)
bool hasAnyMatch = list.Any(item => item > 5); // Returns true as soon as the first item satisfies the condition (replaces explicit iteration)
A simplified version, which should eliminate the flaw:
void timer_Tick(object sender, EventArgs e)
{
if (model.Enemy.Count < 3)
{
logic.AddEnemy();
}
logic.MoveBall();
model.Enemy.ForeEach(logic.MoveEnemy);
model.Enemy.RemoveAll(logic.IsCollidingWithBall);
}
public void AddEnemy()
{
rnd = new Random();
int r = rnd.Next(-300, 300);
model.Enemy.Add(new MyShape(Config.Width / 2 + r, 0, 40, 40));
RefreshScreen?.Invoke(this, EventArgs.Empty);
}
public bool IsCollidingWithBall(MyShape shape)
{
return shape.Area.IntersectsWith(model.Ball.Area);
}
public int MoveEnemy(MyShape shape)
{
shape.ChangeX(shape.Dx);
shape.ChangeY(shape.Dy);
bool hasCollision = model.Enemy.Any(enemy => enemy.Area.IntersectsWith(shape.Area)
&& enemy != shape);
if (hasCollision || shape.Area.Left < 0 || shape.Area.Right > Config.Width - 40)
{
shape.Dx = -shape.Dx;
}
if (shape.Area.Top < 0)
{
shape.Dy = -shape.Dy;
}
if (shape.Area.Bottom > Config.Height / 2)
{
shape.Dy = -shape.Dy;
}
RefreshScreen?.Invoke(this, EventArgs.Empty);
}

messagebox and timer in visual studio

Need help.
so i was making a game with my friend for college using visual studio 2017 and there's something weird about the program.
we're set it so that when the life is zero, a message box would show up and chose whether to retry the game or not, but when we tried the game, the message box show's up at least at 20 - 30 second after playing the game and the timer for the game is still going even though we add "timergame.enable = false;".
where's seems to be the problem?
private void timerGame_Tick(object sender, EventArgs e)
{
for (int i = 0; i < listOfSardine.Count; i++)
{
listOfSardine[i].Top += (int)listOfSardine[i].Tag;
if (listOfSardine[i].Bounds.IntersectsWith(pictureBoxGrass.Bounds))
{
userLives--;
labelLives.Text = "Lives: " + userLives;
listOfSardine[i].Dispose();
listOfSardine.RemoveAt(i);
if (userLives == 0)
{
highScore = userScore;
timerBonusSpeed.Enabled = false;
timerGame.Enabled = false;
timerHealth.Enabled = false;
timerMatatabi.Enabled = false;
timerSardine.Enabled = false;
DialogResult dialogResultLose = MessageBox.Show
("Sorry.... you have lost, continue?", "Continue??", MessageBoxButtons.YesNo);
if (dialogResultLose == DialogResult.Yes)
{
for (int j = 0; j < listOfHealth.Count; j++)
{
listOfHealth[j].Dispose();
}
listOfHealth.Clear();
for (int q = 0; q < listOfSardine.Count; q++)
{
listOfSardine[q].Dispose();
}
listOfSardine.Clear();
for (int k = 0; k < listOfMatatabi.Count; k++)
{
listOfMatatabi[k].Dispose();
}
listOfMatatabi.Clear();
userLives = USER_LIVES;
userScore = USER_SCORE;
timerBonusSpeed.Enabled = true;
timerGame.Enabled = true;
timerHealth.Enabled = true;
timerMatatabi.Enabled = true;
timerSardine.Enabled = true;
}
else
{
this.Visible = false;
FormMainMenu formMainMenu = new FormMainMenu();
formMainMenu.Owner = this;
formMainMenu.ShowDialog();
}
}
}
else if (listOfSardine[i].Bounds.IntersectsWith(pictureBoxMainCharacter.Bounds))
{
listOfSardine[i].Dispose();
listOfSardine.RemoveAt(i);
userScore += 1;
labelScore.Text = "Score: " + userScore;
if (userScore % 100 == 0)
{
listOfSardine[i].Top += (int)listOfSardine[i].Tag * 4;
}
if(userScore == 1000)
{
timerBonusSpeed.Enabled = false;
timerGame.Enabled = false;
timerHealth.Enabled = false;
timerMatatabi.Enabled = false;
timerSardine.Enabled = false;
highScore = userScore;
}
}
else
{
listOfSardine[i].Refresh();
}
}
for (int i = 0; i < listOfHealth.Count; i++)
{
listOfHealth[i].Top += (int)listOfHealth[i].Tag;
if (listOfHealth[i].Bounds.IntersectsWith(pictureBoxGrass.Bounds))
{
listOfHealth[i].Dispose();
listOfHealth.RemoveAt(i);
}
else if (listOfHealth[i].Bounds.IntersectsWith(pictureBoxMainCharacter.Bounds))
{
listOfHealth[i].Dispose();
listOfHealth.RemoveAt(i);
userLives++;
labelLives.Text = "Lives: " + userLives;
}
else
{
listOfHealth[i].Refresh();
}
Not enough clear what you did. However, I think you have a counter for life, and which are decreasing as per your game's event. On timer event just check life counter is equal or less than Zero or not. If so, just stop timer, give user confirmation for retry. If user want to retry, then reset life counter and start timer.
Ahh already found the answer
our problem is about the ownership of the form, we just incorrectly insert the ownership for each form
thanks for the people who have answered my question earlier

How to get count of only visible colums in a WPF datagrid

How can I get count of only visible columns in a WPF datagrid. I am using the count to navigate through the colums present in the datagrid.
if (getSelectedRow().IsEditing)
{
if (dataGrid.SelectedCells.Count != 0)
{
int columnDisplayIndex = dataGrid.CurrentCell.Column.DisplayIndex + 1;
if (columnDisplayIndex <= dataGrid.Columns.Count)
{
if (columnDisplayIndex == dataGrid.Columns.Count)
{
row.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
nextColumn = dataGrid.ColumnFromDisplayIndex(nextCol(1) - 1);
dataGrid.CurrentCell = new DataGridCellInfo(dataGrid.SelectedItem, nextColumn);
}
else
{
e.Handled = true;
nextColumn = dataGrid.ColumnFromDisplayIndex(nextCol(columnDisplayIndex));
dataGrid.CurrentCell = new DataGridCellInfo(dataGrid.SelectedItem, nextColumn);
}
}
}
if (isNotComboBox())
{
dataGrid.CommitEdit();
}
}

Can't get keyListener to work while Timer is running

Hello people of stack overflow, my program has a driver class Frogger(), a JPanel class that calculates everything, pulls together all the necessary panels, and implements keyListener called FroggerPanel(), and another JPanel class that draws everything based on the elements in FroggerPanel() called FroggerDisplayPanel().
Here's a pastebin with the full code: http://pastebin.com/Axrbjej6.
The keyListener works exactly as it should when the Timer isn't started, but as soon as it starts it wont respond at all!
This is where the keyListener is added and focused on in the Frogger() class:
public static void main(String[]args) throws IOException
{
frame = new JFrame("CS125 Frogger");
Frogger startPanel = new Frogger();
FroggerPanel panel = new FroggerPanel();
frame.addKeyListener(panel);
frame.setFocusable(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
This is the stepGame() method in FroggerPanel() that is called when the timer delay expires, its mostly concerned with moving all the cars; the Frog Rectangle in the setLocations() method is what I need to respond to the keyListener:
private int current_x_step = 0;
private int lane_bounds = 0;
private int new_pos = 0;
private void stepGame() {
for (int i = 0; i < laneAmt; i++) {
if(i == 0 || i % 2 == 0){
current_x_step = X_STEP_SIZE;
lane_bounds = display.getWidth()+rUnit;
new_pos = -rUnit;
}else if((i-1) == 0 || (i-1) % 2 == 0){
current_x_step = -X_STEP_SIZE;
lane_bounds = -rUnit;
new_pos = DISPLAY_DIM + rUnit;
}
for(int j = 0; j < cars.get(i).size(); j++){
cars.get(i).get(j).x += current_x_step;
if (cars.get(i).get(j).x == lane_bounds) {
cars.get(i).get(j).x = new_pos;
}
if(cars.get(i).get(j).intersects(Frog)){
timer.stop();
startPause.setText("Retry?");
break;
}
}
}
display.setLocations(cars, Frog);
if(Frog.y == 0){
stepLevel();
}
}
This is the keyListener code thats in the FroggerPanel() class:
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()){
case KeyEvent.VK_W: Frog.y -= rUnit; break;
case KeyEvent.VK_S: Frog.y += rUnit; break;
case KeyEvent.VK_A: Frog.x -= rUnit; break;
case KeyEvent.VK_D: Frog.x += rUnit; break;
}
display.setLocations(cars, Frog);
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
switch(e.getKeyCode()){
case KeyEvent.VK_W: Frog.y -= rUnit; break;
case KeyEvent.VK_S: Frog.y += rUnit; break;
case KeyEvent.VK_A: Frog.x -= rUnit; break;
case KeyEvent.VK_D: Frog.x += rUnit; break;
}
display.setLocations(cars, Frog);
}
Any suggestions are appreciated, thanks for the help!

wpf richtextbox check if caret is in the last line or count how many lines it has

I am trying to find out in a richtext box whether the caret is position in the last line. Is this possible?
NOTE: At the end I also added: or count how many lines it has, this is because in the miscrosoft forum there is an example for detecting in which line the caret is.
thanks
Please verify the msdn link
http://social.msdn.microsoft.com/Forums/en/wpf/thread/667b5d2a-84c3-4bc0-a6c0-33f9933db07f
If you really wanted to know the line number of the caret, you could do something like the following (probably needs some tweaking):
TextPointer caretLineStart = rtb.CaretPosition.GetLineStartPosition(0);
TextPointer p = rtb.Document.ContentStart.GetLineStartPosition(0);
int caretLineNumber = 1;
while (true)
{
if (caretLineStart.CompareTo(p) < 0)
{
break;
}
int result;
p = p.GetLineStartPosition(1, out result);
if (result == 0)
{
break;
}
caretLineNumber++;
}
The code to get the number of lines:
Int32 CountDisplayedLines(RichTextBox rtb)
{
Int32 result = -1;
rtb.CaretPosition = rtb.Document.ContentStart;
while (rtb.CaretPosition.GetLineStartPosition(++result) != null)
{
}
return result;
}
I have found a solution. Maybe there is a simpler way, if so please let me know
private void OnHasRtbReachedEnd(System.Windows.Controls.RichTextBox rtb)
{
TextPointer pointer1 = rtb.CaretPosition;
int iCurrentLine = GetLineNumber(rtb);
rtb.CaretPosition = rtb.Document.ContentEnd;
int iLastLine = GetLineNumber(rtb);
if (iCurrentLine == iLastLine)
{
if (!_bIsRtbMovingUpDown)
MoveToNextDataGridRow();
_bIsRtbMovingUpDown= false;
}
else
{
_bIsRtbMovingUpDown= true;
}
rtb.CaretPosition = pointer1;
}
//This code comes from
//http://social.msdn.microsoft.com/Forums/en/wpf/thread/667b5d2a-84c3-4bc0-a6c0-33f9933db07f
private int GetLineNumber(System.Windows.Controls.RichTextBox rtb)
{
TextPointer caretLineStart = rtb.CaretPosition.GetLineStartPosition(0);
TextPointer p = rtb.Document.ContentStart.GetLineStartPosition(0);
int caretLineNumber = 1;
while (true)
{
if (caretLineStart.CompareTo(p) < 0)
{
break;
}
int result;
p = p.GetLineStartPosition(1, out result);
if (result == 0)
{
break;
}
caretLineNumber++;
}
return caretLineNumber;
}
I tried the code and is not giving correct results always.
One smart way to do it is this
int previousCursorPosition;
private void RichTarget_KeyDown_1(object sender, KeyEventArgs e)
{
if (e.Key == Key.Up || e.Key == Key.Down)
{
Xceed.Wpf.Toolkit.RichTextBox rich = (Xceed.Wpf.Toolkit.RichTextBox)sender;
previousCursorPosition = rich.CaretPosition.GetOffsetToPosition(rich.CaretPosition.DocumentStart);
}
}
private void RichTextBox_KeyUp_1(object sender, KeyEventArgs e)
{
if (e.Key == Key.Up)
{
Xceed.Wpf.Toolkit.RichTextBox rich = (Xceed.Wpf.Toolkit.RichTextBox)sender;
if (previousCursorPosition == rich.CaretPosition.GetOffsetToPosition(rich.CaretPosition.DocumentStart))
{
//do your staff
}
}
else if (e.Key == Key.Down)
{
Xceed.Wpf.Toolkit.RichTextBox rich = (Xceed.Wpf.Toolkit.RichTextBox)sender;
if (previousCursorPosition == rich.CaretPosition.GetOffsetToPosition(rich.CaretPosition.DocumentStart))
{
//do your staff
}
}
}

Resources