Tooltip on scrollviewer in documentviewer - wpf

I have a documentviewer which i used in my wpf project to show xps document reports of having around 600 pages which is working great. But from user point of view i like to show the current page number as a tooltip on my scrollviewer while dragging the scroll stating the current page number in view. Somewhat like in a PDF file like this -
I was looking out for some ideas how to implement this. Just a current page number if not possible to show a thumbnail image would be good enough for me.
Is there any in-built support in documentviewer for this functionality??
Thanks for any help..

I cannot find anything like IsScrolling so i would approach it like this:
<Popup Name="docPopup" AllowsTransparency="True" PlacementTarget="{x:Reference docViewer}" Placement="Center">
<Border Background="Black" CornerRadius="5" Padding="10" BorderBrush="White" BorderThickness="1">
<TextBlock Foreground="White">
<Run Text="{Binding ElementName=docViewer, Path=MasterPageNumber, Mode=OneWay}"/>
<Run Text=" / "/>
<Run Text="{Binding ElementName=docViewer, Path=PageCount, Mode=OneWay}"/>
</TextBlock>
</Border>
</Popup>
<DocumentViewer Name="docViewer" ScrollViewer.ScrollChanged="docViewer_ScrollChanged"/>
The popup should be displayed when the document is scrolled, then it should fade out after some time. This is done in the handler:
DoubleAnimationUsingKeyFrames anim;
private void docViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
if (anim == null)
{
anim = new DoubleAnimationUsingKeyFrames();
anim.Duration = (Duration)TimeSpan.FromSeconds(1);
anim.KeyFrames.Add(new DiscreteDoubleKeyFrame(1, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(0))));
anim.KeyFrames.Add(new DiscreteDoubleKeyFrame(1, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(0.5))));
anim.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(1))));
}
anim.Completed -= anim_Completed;
docPopup.Child.BeginAnimation(UIElement.OpacityProperty, null);
docPopup.Child.Opacity = 1;
docPopup.IsOpen = true;
anim.Completed += anim_Completed;
docPopup.Child.BeginAnimation(UIElement.OpacityProperty, anim);
}
void anim_Completed(object sender, EventArgs e)
{
docPopup.IsOpen = false;
}
Edit: The event fires also on scrolls done via mouse-wheel etc. you could wrap everything in the handler in if (Mouse.LeftButton == MouseButtonState.Pressed), not 100% accurate but who scrolls with the MouseWheel while left-clicking?

Related

Update ScrollView when image is resized (WPF)

I'm doing a graphic editor for a GBA game and I got an image into a ScrollView. When the user click on a NumericUpDown, the image is resized with a magnify factor. I would like my ScrollView to adapt itself to the new size of the image to be able to scroll the entire image. I'm not using the MVVM patter.
Here is portion of my XAML:
<ScrollViewer x:Name="PortraitScrollBar" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" VerticalAlignment="Bottom" HorizontalAlignment="Right">
<Image x:Name="ImagePortrait" Width="280" Height="280" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top" />
</ScrollViewer>
Here also is my function that is called on the ValueChanged event of the NumericUpDown:
public static void Magnify(ref Image img, WriteableBitmap wBmp, int factor)
{
img.Source = wBmp.Resize(wBmp.PixelWidth * factor, wBmp.PixelHeight * factor, WriteableBitmapExtensions.Interpolation.NearestNeighbor);
}
private void PorMagnifyUpDown_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (IsInit)
{
Magnify(ref ImagePortrait, currentImage, (int)e.NewValue);
}
}

How to change collection images in silverlight?

My Design Code like this:
<Grid HorizontalAlignment="Left" Height="42" VerticalAlignment="Top" Width="302" Margin="12,471,0,0" Background="{StaticResource AppBarItemForegroundThemeBrush}">
<TextBlock HorizontalAlignment="Left" Margin="6,6,0,0" TextWrapping="Wrap" Text="Change Color" VerticalAlignment="Top" Height="26" Width="137" FontSize="18" Foreground="Black" />
<Image HorizontalAlignment="Left" Height="33" Margin="163,3,0,0" VerticalAlignment="Top" Width="41" Source="Assets/c1-1.png" x:Name="c1" Tapped="c1_Tapped" />
<Image HorizontalAlignment="Left" Height="32" Margin="212,4,0,0" VerticalAlignment="Top" Width="45" Source="Assets/c3-1.png" x:Name="c2" Tapped="c2_Tapped" RenderTransformOrigin="0.825,0.5" />
<Image HorizontalAlignment="Left" Height="33" Margin="262,3,0,0" VerticalAlignment="Top" Width="40" Source="Assets/c2-1.png" x:Name="c3" Tapped="c3_Tapped" />
</Grid>
Code Behind code like this:
private void c1_Tapped(object sender, TappedRoutedEventArgs e)
{
Images = new ObservableCollection<string>();
Images.Add(#"Assets/02_perspective_img_1.png");
Images.Add(#"Assets/02_perspective_img_2.png");
Images.Add(#"Assets/02_perspective_img_3.png");
this.DataContext = this;
}
private void c2_Tapped(object sender, TappedRoutedEventArgs e)
{
Images = new ObservableCollection<string>();
Images.Add(#"Assets/03_perspective_img_1.png");
Images.Add(#"Assets/03_perspective_img_2.png");
Images.Add(#"Assets/03_perspective_img_3.png");
this.DataContext = this;
}
private void c3_Tapped(object sender, TappedRoutedEventArgs e)
{
Images = new ObservableCollection<string>();
Images.Add(#"Assets/01_perspective_img_1.png");
Images.Add(#"Assets/01_perspective_img_2.png");
Images.Add(#"Assets/01_perspective_img_3.png");
this.DataContext = this;
}
When tapped on particular image need to show that particular images.But not showing that .
only showing first clicked items images only.Please let me know how to change the collection.
i am binding that collection to flipview control in windows 8.
<FlipView.ItemTemplate>
<DataTemplate>
<Image HorizontalAlignment="Left" Source="{Binding}" Height="450" VerticalAlignment="Top" Width="792" x:Name="imagecontrol" Stretch="Fill"/>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
I'm going under a few assumptions. One is that the FlipView control has it's ItemsSource binding to your Images property. If you are going to set the DataContext to yourself (the page in question) you need to do one of a few options.
One: Do not set Images to a new collection. You are using an ObservableCollection so take advantage of it. Clear the collection and add items back to it.
private void c3_Tapped(object sender, TappedRoutedEventArgs e)
{
Images.Clear();
Images.Add(#"Assets/01_perspective_img_1.png");
Images.Add(#"Assets/01_perspective_img_2.png");
Images.Add(#"Assets/01_perspective_img_3.png");
}
Two: Implement INotifyPropertyChanged in the page and fire the PropertyChanged event when you reset the Images property
private ICollection<string> _images;
public ICollection<string> Images
{
get { return _images; }
set
{
_images = value;
OnPropertyChanged("Images");
}
}
You will probably find that you will need more and more bindings. Because of this it is usually best to have a separate ViewModel class that holds your data.
the way Shawn is suggested is i will recommend but when i tested it in case of Windows 8 app page which is inherited by LayoutAwarePage then in that case - Firstly you got error that Page Can not Implement InotifypropertyChanged secondly when i Tested it With ObsevableCollection that time also it is not working..so i have come with this workaround for solving your problem. in this case you just have to update the itemsSource Property of your FlipView Control each time when you are updating your Image collection..
private void c1_Tapped(object sender, TappedRoutedEventArgs e)
{
Images = new ObservableCollection<string>();
Images.Add(#"Assets/02_perspective_img_1.png");
Images.Add(#"Assets/02_perspective_img_2.png");
Images.Add(#"Assets/02_perspective_img_3.png");
FlipviewControlName.ItemsSource = Images;
}
I know this is not the proper solution but i think i will solve your problem...

TextBlock MouseDown URL - How get my url in my code behind?

I ve a list from sharepoint and i collect from this list an hyperlink.
As i want my textbox to be like an hyperlink I ve added an event on mousedown to open this hyperlink, My concern is how to collect this hyperlink in the codebehind with the sender.
For the moment I've just hide this hyperlink in the tooltip maybe i can manage this differently any suggestion will be grantly appreciated.
My point so far, i don't know how to get this tooltip in the code behind.
Thanks
My XAML Code :
<ListBox Name="ListboxTips" ItemsSource="{Binding}" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Path=Picture}" Height="20"></Image>
<TextBlock MouseDown="TextBlock_MouseDown_URL" TextDecorations="Underline"
Margin="10,10,20,10" Width="160" TextWrapping="Wrap"
Text="{Binding Path=TitleTip}"
ToolTip="{Binding Path=URL}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My code behind :
foreach (SPSClient.ListItem item in TipsList)
{
var tips = new Tips();
tips.TitleTip = item.FieldValues.Values.ElementAt(1).ToString();
tips.App = item.FieldValues.Values.ElementAt(4).ToString();
// get the Hyperlink field URL value
tips.URL = ((FieldUrlValue)(item["LinkDoc"])).Url.ToString();
//should collect the description of the url
//tips.URLdesc = ((FieldUrlValue)(item["LinkDoc"])).Description.ToString();
tips.Picture = item.FieldValues.Values.ElementAt(4).ToString();
colTips.Add(tips);
}
ListboxTips.DataContext = colTips;
....
private void TextBlock_MouseDown_URL(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
//string test = (ToolTip)(sender as Control).ToString();
System.Diagnostics.Process.Start("http://www.link.com");
//System.Diagnostics.Process.Start(test);
}
Thanks a lot,
You can just access the property directly. It is not elegant, but will work!
private void TextBlock_MouseDown_URL(object sender, MouseButtonEventArgs e)
{
TextBlock txtBlock = sender as TexBlock;
// just access the property
string url = txtBlock.ToolTip as string;
}
A more elegant approach might be to use a Button, Hyperlink or something that exposes a Command, so that you can bind the 'click' action to a command on your view model that performs the action you wish to execute.
usually you stick any data you want to trespass somewhere to Tag attribute.
<TextBlock .. Tag="{Binding Path=URL}" />
This is easily retrievable as a public property:
private void TextBlock_MouseDown_URL(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
var tb = sender as TextBlock;
if(tb != null)
{
var neededUrl = tb.Tag;
}
}

Prevent phone from sending MouseLeftButtonUp event while scrolling

How can I prevent the windows phone 7 from sending a MouseLeftButtonUp-event to my Grid (that I use as Button) while the user is scrolling?
This issue sometimes leads to a navigation to another page just when the user scrolling.
Or should I use a Button-Template for this?
Example code:
<ScrollViewer>
<StackPanel>
<Grid x:Name="Button1" MouseLeftButtonUp="Button1_LeftMouseButtonUp">
<TextBlock Margin="12 15" />
</Grid>
</StackPanel>
</ScrollViewer>
Instead of LeftMouseButtonUp event try this
private void Button1_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
if (!e.IsInertial)
{
//Button Click Code
}
}

Open a popup during mouseover of listbox textblock

Photosuru has a neat effect - when you mouseover the thumbnail image a popup opens showing the image enlarged. I am trying to get this to work on a listbox, similar to a tooltip, I need to mouseover an item and have the popup open. The problem, the popup only shows the item selected in the listbox. I tried looking through Photosuru code for the answer, but found it too advanced for me. Note: I can't use tooltip as it is needed for something else.
Here's the xaml:
<Window.Resources>
<XmlDataProvider x:Key="MyPartsXML"
Source="F:\ListBoxSync\MyParts.xml"
XPath="MyParts"/>
</Window.Resources>
<Grid x:Name="MainGrid"
DataContext="{Binding ElementName=PartsList, Path=SelectedItem}"
Width="Auto"
VerticalAlignment="Stretch">
<ListBox ItemsSource="{Binding Source={StaticResource MyPartsXML},
XPath=//MyParts//parts}"
IsSynchronizedWithCurrentItem="True"
Name="PartsList"
HorizontalAlignment="Left">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="2" BorderBrush="Black" Margin="10">
<TextBlock Name="lstbxBlock"
Text="{Binding XPath=item}"
MouseEnter="item_MouseEnter"
MouseLeave="item_MouseLeave"/>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Popup x:Name="Pops"
IsOpen="False"
Placement="Right"
StaysOpen="False"
PlacementTarget="{Binding ElementName=txtBxitem}"
HorizontalAlignment="Left">
<StackPanel>
<TextBox Text="{Binding XPath=color}"/>
<TextBox Text="{Binding XPath=size}"/>
</StackPanel>
</Popup>
<TextBox Text="{Binding XPath=color}"/>
<TextBox Text="{Binding XPath=size}"/>
</Grid>
The code behind:
private void item_MouseEnter(object sender, MouseEventArgs e)
{
this.Pops.IsOpen = true;
}
private void item_MouseLeave(object sender, MouseEventArgs e)
{
this.Pops.IsOpen = false;
}
Hope this isn't overkill, but here's the xml:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<MyParts>
<parts>
<item>Part1</item>
<color>Red</color>
<size>SM</size>
</parts>
<parts>
<item>Part2</item>
<color>Green</color>
<size>LG</size>
</parts>
<parts>
<item>Part3</item>
<color>Blue</color>
<size>XXL</size>
</parts>
<parts>
<item>Part4</item>
<color>Yellow</color>
<size>LG</size>
</parts>
<parts>
<item>Part5</item>
<color>Green</color>
<size>XL</size>
</parts>
First, thanks for your excellent sample code to reproduce your issue. The problem is that the data context of the popup is never set so it gets it from it parent, the grid which you set to currently selected item. In the code behind you can set the correct data contect of the popup.
private void item_MouseEnter(object sender, MouseEventArgs e)
{
Pops.DataContext = (sender as FrameworkElement).DataContext;
Pops.PlacementTarget = (sender as UIElement);
Pops.IsOpen = true;
}
Also, you can't set the placement target like you do in xaml, it is not possible to just reference a control in a data template. The code behind fix will set placement target but hide your regular tooltip unless you add an offset to one of them. Personally I don't think its a good idea to have two popups on mouse over.
<html>
<title>CodeAve.com(JavaScript: Hover
Window within Previous Page)</title>
<body bgcolor="#FFFFFF">
<script language="JavaScript">
<!--
// This is the function that will open the
// new window when the mouse is moved over the link
function open_new_window()
{
new_window = open("","hoverwindow","width=300,height=200,left=10,top=10");
// open new document
new_window.document.open();
// Text of the new document
// Replace your " with ' or \" or your document.write statements will fail
new_window.document.write("<html><title>JavaScript New Window</title>");
new_window.document.write("<body bgcolor=\"#FFFFFF\">");
new_window.document.write("This is a new html document created by JavaScript ");
new_window.document.write("statements contained in the previous document.");
new_window.document.write("<br>");
new_window.document.write("</body></html>");
// close the document
new_window.document.close();
}
// This is the function that will close the
// new window when the mouse is moved off the link
function close_window()
{
new_window.close();
}
// -->
</script>
Open Hover Window
</body>
</html>
Some code I found that completes this using simple Javascript. You could definitely incorporate this into .NET using your custom controls pretty easily. This shows how the functionality of the popup should be setup though.

Resources