How to set background image globally windows phone 8.1? - xaml

I'm brand new to windows phone and it seems like windows phone 8.1 has lots of changes compare with windows phone 8. How can I change the background image for my app globally, without declare it again and again in every single views.

Declare the ImageBrush in your App.xaml
<Application x:Class="App1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1">
<Application.Resources>
<ImageBrush x:Key="BgImage" ImageSource="Assets/Logo.png" />
</Application.Resources>
</Application>
Set the Background of your rootFrame in App.xaml.cs -> OnLaunched method:
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
#if DEBUG
if (System.Diagnostics.Debugger.IsAttached)
{
this.DebugSettings.EnableFrameRateCounter = true;
}
#endif
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame == null)
{
rootFrame = new Frame();
// TODO: diesen Wert auf eine Cachegröße ändern, die für Ihre Anwendung geeignet ist
rootFrame.CacheSize = 1;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
// TODO: Zustand von zuvor angehaltener Anwendung laden
}
Window.Current.Content = rootFrame;
}
if (rootFrame.Content == null)
{
if (rootFrame.ContentTransitions != null)
{
this.transitions = new TransitionCollection();
foreach (var c in rootFrame.ContentTransitions)
{
this.transitions.Add(c);
}
}
rootFrame.ContentTransitions = null;
rootFrame.Navigated += this.RootFrame_FirstNavigated;
if (!rootFrame.Navigate(typeof(MainPage), e.Arguments))
{
throw new Exception("Failed to create initial page");
}
}
rootFrame.Background = (ImageBrush)Resources["BgImage"];
Window.Current.Activate();
}
And than make your page background transparent.
Here is my Page.xaml:
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<TextBlock Text="Hello World !"/>
</Grid>
</Page>
Hope it helps

Related

MyCustomPage.xaml is not loading webView in xamarin.Forms portable

I am beginner in xamarin.forms portable, i am working on xamainr.forms portable project, there i am facing issue. I have a .xaml page in my portable project and i am navigating to this .xaml page from App.cs using following line of code.
var ep = new CustomWebViewPage(dbPath);
var MainEv = new NavigationPage(ep);
Here in CustomWebViewPage i am using WebView in following way to load Url but after successful execution above lines emulator does not load webView. I don't know why it is happening.
I am pasting code of CustomWebViewPage as following.
CustomWebViewPage.xaml.cs
using XamarinDbokReader.SQLite_AppSample;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using System.IO;
namespace MyDummyProject
{
public partial class CustomWebViewPage : ContentPage
{
public string dbPath = "";
public CustomWebViewPage(string folderPath)
{
this.dbPath = folderPath;
HttpHelperClass helperClass = new HttpHelperClass();
InitializeComponent();
var webView = new WebView();
UrlWebViewSource urlWebViewSource = new UrlWebViewSource()
{
Url = UrlsList.FindUrl("ProEportalLoginPage") + UrlsList.ApiKeys(AppMode.ProductionMode.ToString())
};
webView.Source = urlWebViewSource;
webView.Navigated += (s, e) =>
{
if (e.Url.StartsWith("http://userInfo/?"))
{
string token = "";
try
{
string value_string = Uri.UnescapeDataString(e.Url.ToString());
token = value_string.Split('=')[1];
if (!string.IsNullOrEmpty(token))
{
string path = Path.Combine(dbPath.ToString(), "dBookStore.db3");
helperClass.SaveUserInformation(token, path);
}
}
catch (Exception ss)
{
}
}
};
wvEportalPage = webView;
}
public CustomWebViewPage()
{
}
}
}
CustomWebViewPage.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="XamarinDbokReader.EportalPage">
<Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" />
<WebView x:Name="wvEportalPage"></WebView>
</ContentPage>
App.cs
public App(bool isSqliteDbExist, string sPath)
{
isDbExist = isSqliteDbExist;
dbPath = sPath;
if (isDbExist)
{
if (isLoggedIn)
{
NavigationPage navPage = new NavigationPage(new BooksView());
App.Current.MainPage = navPage;
}
else
{
var tdlx = new CustomWebViewPage(dbPath);
var MainNave = new NavigationPage(tdlx);
}
}
else
{
//When cursor is coming from MainActivity then following line executes. And then OnStart() method executes.
ssd.CreateTablesInDb();
isDbExist = true;
}
}
protected override void OnStart()
{
if (isDbExist)
{
if (isLoggedIn)
{
NavigationPage navPage = new NavigationPage(new BooksView());
App.Current.MainPage = navPage;
}
else
{
var ep = new CustomWebViewPage(dbPath);
var MainEv = new NavigationPage(ep);
}
}
}
MainActivity
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
var documents = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
var bookCoverFolder = Path.Combine(documents, "BooksCover");
var booksCollection = Path.Combine(documents, "Books");
var bookResource = Path.Combine(documents, "Resource");
if(!Directory.Exists(bookCoverFolder))
Directory.CreateDirectory(bookCoverFolder);
if (!Directory.Exists(booksCollection))
Directory.CreateDirectory(booksCollection);
if(!Directory.Exists(bookResource))
Directory.CreateDirectory(bookResource);
SQLite_Android androidDb = new SQLite_Android();
if (androidDb.IsExist())
{
LoadApplication(new App(true, androidDb.dbStorePath));
}
else
{
LoadApplication(new App(false, androidDb.dbStorePath));
}
}
The WebView probably isn't getting any Width or Height.
Try setting the VerticalOptions and HorizontalOptions properties to FillAndExpand.
So like this:
<?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="XamarinDbokReader.EportalPage">
<Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" />
<WebView x:Name="wvEportalPage" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"></WebView>
</ContentPage>
If that doesn't seem to work try wrapping it in a Grid.
Thank you for awesome sugessions, but i found my mistake in code.I did a very small mistake in App.cs After setting navigation page i am not setting NavigationPage to MainPage. It should as below.
var tdlx = new CustomWebViewPage(dbPath);
var MainNave = new NavigationPage(tdlx);
MainPage = MainNave;
it worked perfectly. I knew about MainPage but i have not written due to some other regions but ultimately it is working.
You must define Width and Height to Xamarin WebView.

Issues when saving files to OneDrive on Windows 10 Mobile

I’m working on an application where you should be able to open and save files, similar to “Notepad”. It’s a universal application that should work both on computers and mobiles.
The application works fine on computers. It also works fine on mobile if I save or open files locally or on Dropbox.
But if I open a file on OneDrive (via the file picker), and then try to save an exception is thrown: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
If I select “Save as” on OneDrive it works. But every time I select Save after this a new instance of the file is created (I get “file 1”, “file 2”, “file 3” and so on).
I have only tested this on my phone. I might have a bug on my application, but since it works on DropBox I don’t think so. Is this a known issue with OneDrive? Or might I just have some local issues? I’m using Windows 10 Mobile 10.10586.420 and OneDrive 17.11.
Here is some code to illustrate the problem:
<Page
x:Class="BasicEditor.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:BasicEditor"
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}" Margin="40">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<Button Content="Open"
Click="OpenButton_Click" />
<Button Content="Save"
Click="SaveButton_Click" />
<Button Content="Save as"
Click="SaveAsButton_Click" />
</StackPanel>
<TextBox Grid.Row="1" x:Name="TextEditor"
TextWrapping="Wrap" />
</Grid>
</Page>
using System;
using System.Collections.Generic;
using Windows.Storage;
using Windows.Storage.AccessCache;
using Windows.Storage.Pickers;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace BasicEditor
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
string MruToken;
private async void OpenButton_Click(object sender, RoutedEventArgs e)
{
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.List;
openPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
openPicker.FileTypeFilter.Add(".txt");
StorageFile file = await openPicker.PickSingleFileAsync();
if (file != null)
{
try
{
string fileContent = await FileIO.ReadTextAsync(file);
TextEditor.Text = fileContent;
string token = Windows.Storage.AccessCache.StorageApplicationPermissions.MostRecentlyUsedList.Add(file, "");
MruToken = token;
}
catch (Exception ex)
{
System.Diagnostics.Debug.Write($"Open-Error: {ex.Message}");
var dialog = new MessageDialog($"Open-Error: {ex.Message}");
await dialog.ShowAsync();
}
}
}
private async void SaveButton_Click(object sender, RoutedEventArgs e)
{
try
{
var file = await StorageApplicationPermissions.MostRecentlyUsedList.GetFileAsync(MruToken);
string fileContent = await FileIO.ReadTextAsync(file);
await FileIO.WriteTextAsync(file, TextEditor.Text);
var dialog = new MessageDialog($"Saved successfully");
await dialog.ShowAsync();
}
catch (Exception ex)
{
System.Diagnostics.Debug.Write($"Save-Error: {ex.Message}");
var dialog = new MessageDialog($"Save-Error: {ex.Message}");
await dialog.ShowAsync();
}
}
private async void SaveAsButton_Click(object sender, RoutedEventArgs e)
{
FileSavePicker savePicker = new FileSavePicker();
savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
savePicker.FileTypeChoices.Add("Plain Text", new List<string>() { ".txt" });
savePicker.SuggestedFileName = "New Document";
StorageFile file = await savePicker.PickSaveFileAsync();
if (file != null)
{
try
{
await FileIO.WriteTextAsync(file, TextEditor.Text);
string token = Windows.Storage.AccessCache.StorageApplicationPermissions.MostRecentlyUsedList.Add(file, "");
MruToken = token;
}
catch (Exception ex)
{
System.Diagnostics.Debug.Write($"SaveAs-Error: {ex.Message}");
var dialog = new MessageDialog($"SaveAs-Error: {ex.Message}");
await dialog.ShowAsync();
}
}
}
}
}
A beta of my app is available here: https://www.microsoft.com/store/apps/9NBLGGH3MFM3
Another app with exactly the behavior when OneDrive is used is NotepadX.

Adding MenuFlyout to a RichEditBox UWP

Is it possible to add a menu flyout to a RichEditBox in UWP in addition to already available flyout items. But i see that there is no flyout property in richeditbox. So is it possible to add one? If Yes please provide the steps to add a menuFlyout. Thanks in advance!
Ofcourse its possible.
<RichEditBox GotFocus="RichEditBox_GotFocus">
<FlyoutBase.AttachedFlyout>
<Flyout>
<Button Content="test"/>
</Flyout>
</FlyoutBase.AttachedFlyout>
</RichEditBox>
private void RichEditBox_GotFocus(object sender, RoutedEventArgs e)
{
FlyoutBase.ShowAttachedFlyout((sender as RichEditBox));
}
Update
I tried implementing your requirement without custom flyout.
Observations
1 RightTapped event doesnt fire for Textbox. Not sure why. There
is ScrollViewer in ControlTemplate of TextBox(May be that is
the reason why RightTapped event not firing in Textbox)So I added
RightTapped event for Scrollviewer.
2.
private async void ContentElement_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
FlyoutBase.ShowAttachedFlyout(textbox);
await Task.Delay(1000);
FlyoutPresenter canvas = testbutton.FindParent<FlyoutPresenter>();
var popup = canvas.Parent as Popup;
double x = e.GetPosition(e.OriginalSource as UIElement).X;
Debug.WriteLine(x);
popup.IsOpen = false;
popup.SetValue(Canvas.LeftProperty, e.GetPosition(e.OriginalSource as UIElement).X);
popup.IsOpen = true;
}
<Style x:Key="RichEditBoxStyle1" TargetType="RichEditBox">
...
<ScrollViewer x:Name="ContentElement" IsRightTapEnabled="True" RightTapped="ContentElement_RightTapped" AutomationProperties.AccessibilityView="Raw" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" IsTabStop="False" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" Margin="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" Grid.Row="1" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" ZoomMode="Disabled"/>
...
</Style>
<RichEditBox x:Name="textbox" Width="400" HorizontalAlignment="Left" Grid.Row="3" RightTapped="RichEditBox_RightTapped" IsRightTapEnabled="True" GotFocus="RichEditBox_GotFocus" Style="{StaticResource RichEditBoxStyle1}">
<FlyoutBase.AttachedFlyout>
<Flyout >
<Button Content="test" x:Name="testbutton" Click="Button_Click"/>
</Flyout>
</FlyoutBase.AttachedFlyout>
</RichEditBox>
In above code ContentElement_RightTapped is RightTapped Event of ScrollViewer. To add this You have to edit Style of TextBox.
Basically flyout conatins popup that i'm getting using VisualTreeHelper. And setting position(which i get from the event) of PopUp. But somehow PopUp is not getting set to the exact position.
So second option is to go for custom flyout. Refer this Link for how to implement one . You can take code from there
Here is the modified code code
public class TemplatedFlyout:DependencyObject
{
public TemplatedFlyout()
{
}
Popup popUp;
FrameworkElement senderElement;
FrameworkElement frameworkContent;
bool keyboardOpen = false;
InputPane keyboard;
public void Initialization(UIElement sender)
{
senderElement = sender as FrameworkElement;
senderElement.DataContextChanged += (s, e) =>frameworkContent.DataContext = senderElement.DataContext;
popUp = new Popup()
{
ChildTransitions = new Windows.UI.Xaml.Media.Animation.TransitionCollection(),
IsLightDismissEnabled = true
};
popUp.ChildTransitions.Add(new PaneThemeTransition() { Edge = EdgeTransitionLocation.Bottom });
frameworkContent = Template as FrameworkElement;
frameworkContent.DataContext = senderElement.DataContext;
popUp.Child = frameworkContent;
FocusKeeper();
if(sender is RichEditBox || sender is TextBox)
{
(sender as FrameworkElement).Loaded += TemplatedFlyout_Loaded;
}
//else
// sender.Tapped += (s, e) => Show(e);
}
private void TemplatedFlyout_Loaded(object sender, RoutedEventArgs e)
{
(sender as FrameworkElement).FindElementInVisualTree<ScrollViewer>().RightTapped += (s, e1) => Show(e1);
}
public static readonly DependencyProperty TemplateProperty = DependencyProperty.Register(nameof(Template), typeof(object), typeof(TemplatedFlyout), new PropertyMetadata(null));
public object Template
{
get { return (object) GetValue(TemplateProperty); }
set { SetValue(TemplateProperty, value); }
}
void FocusKeeper()
{
keyboard = InputPane.GetForCurrentView();
popUp.Closed += (s, e) =>
{
if(keyboardOpen)
{
popUp.IsOpen = true;
}
};
if(keyboard!=null)
{
keyboard.Showing += (s, e) => keyboardOpen = true;
keyboard.Hiding += (s, e) => keyboardOpen = false;
}
}
public async void Show(RightTappedRoutedEventArgs args)
{
try
{
popUp.RequestedTheme = ((Window.Current.Content as Frame).Content as Page).RequestedTheme;
popUp.IsOpen = true;
frameworkContent.UpdateLayout();
var top = Math.Abs(senderElement.ActualHeight+frameworkContent.ActualHeight+10-Window.Current.Bounds.Height);
var left = args.GetPosition(args.OriginalSource as UIElement).X;
if (frameworkContent is Panel)
{
var panel = frameworkContent as Panel;
if (panel.Children.Any())
{
if (panel.Children.First() is Control)
{
(panel.Children.First() as Control).Focus(FocusState.Keyboard);
}
}
}
popUp.SetValue(Canvas.TopProperty, top);
popUp.SetValue(Canvas.LeftProperty, left);
}
catch(Exception e)
{
}
}
}
public class Extensions:DependencyObject
{
public static void SetFlyout(UIElement element, TemplatedFlyout value)
{
element.SetValue(FlyoutProperty, value);
}
public static TemplatedFlyout GetFlyout(UIElement element)
{
return (TemplatedFlyout)element.GetValue(FlyoutProperty);
}
public static readonly DependencyProperty FlyoutProperty = DependencyProperty.Register(nameof(FlyoutProperty), typeof(TemplatedFlyout), typeof(Extensions), new PropertyMetadata(null, TemplateFlyoutChanged));
private static void TemplateFlyoutChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var uiSender = d as UIElement;
var flyout = e.NewValue as TemplatedFlyout;
flyout.Initialization(uiSender);
}
}
public static class VisualExtensions
{
public static T FindElementInVisualTree<T>(this DependencyObject parentElement) where T : DependencyObject
{
var count = VisualTreeHelper.GetChildrenCount(parentElement);
if (count == 0) return null;
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(parentElement, i);
if (child != null && child is T)
return (T)child;
else
{
var result = FindElementInVisualTree<T>(child);
if (result != null)
return result;
}
}
return null;
}
}
<RichEditBox IsRightTapEnabled="True" >
<local:Extensions.Flyout>
<local:TemplatedFlyout >
<local:TemplatedFlyout.Template>
<StackPanel>
<TextBlock Text="test1"/>
<TextBlock Text="test1"/>
</StackPanel>
</local:TemplatedFlyout.Template>
</local:TemplatedFlyout>
</local:Extensions.Flyout>
</RichEditBox>
Update 2
You cant add to existing Contextmenu of TextBox. To modify the context menu here is the sample

Custom CommandBar to PickerFlyout

By default PickerFlyout has commandbar that has done and cancel buttons. Is it possible to disable done button programmatically? If not is there any way to add custom command bar and replace default one?
With the help of the answer given i tried to write custom picker from PickerFlyoutBase. But now i'm not able to add content to flyout in xaml. Giving me error saying custompicker doesnt support direct content
<Button>
<Button.Flyout>
<local:custompicker>
<TextBlock Margin="20" FontSize="30" Text="MyPickerFlyout Test" />
</local:custompicker>
</Button.Flyout>
</Button
public class custompicker:PickerFlyoutBase
{
private AppBar OriginalAppBar;
private CommandBar MyCommandBar;
private Page CurrentPage;
public custompicker()
{
var cancelButton = new AppBarButton();
cancelButton.Icon = new SymbolIcon(Symbol.Cancel);
cancelButton.Label = "Cancel";
cancelButton.Click += (s, e) =>
{
this.Hide();
};
MyCommandBar = new CommandBar();
MyCommandBar.PrimaryCommands.Add(cancelButton);
this.Closed += MyPickerFlyout_Closed;
this.Opening += MyPickerFlyout_Opening;
this.Placement = Windows.UI.Xaml.Controls.Primitives.FlyoutPlacementMode.Full;
}
private void MyPickerFlyout_Opening(object sender, object e)
{
CurrentPage = (Windows.UI.Xaml.Window.Current.Content as Frame).Content as Page;
if (CurrentPage != null)
{
OriginalAppBar = CurrentPage.BottomAppBar;
CurrentPage.BottomAppBar = MyCommandBar;
}
}
private void MyPickerFlyout_Closed(object sender, object e)
{
if (CurrentPage != null)
{
CurrentPage.BottomAppBar = OriginalAppBar;
}
}
}
PickerFlyout class has a ConfirmationButtonsVisible property, we can use this property to disable both "Done" and "Cancel" button.
But there is no way to disable only "Done" button. We have to implement a custom "PickerFlyout". Following is a simple custom "PickerFlyout" based on Flyout, you can refer to it to implement your own.
public class MyPickerFlyout : Flyout
{
private AppBar OriginalAppBar;
private CommandBar MyCommandBar;
private Page CurrentPage;
public MyPickerFlyout()
{
var cancelButton = new AppBarButton();
cancelButton.Icon = new SymbolIcon(Symbol.Cancel);
cancelButton.Label = "Cancel";
cancelButton.Click += (s, e) =>
{
this.Hide();
};
MyCommandBar = new CommandBar();
MyCommandBar.PrimaryCommands.Add(cancelButton);
this.Closed += MyPickerFlyout_Closed;
this.Opening += MyPickerFlyout_Opening;
this.Placement = Windows.UI.Xaml.Controls.Primitives.FlyoutPlacementMode.Full;
}
private void MyPickerFlyout_Opening(object sender, object e)
{
CurrentPage = (Windows.UI.Xaml.Window.Current.Content as Frame)?.Content as Page;
if (CurrentPage != null)
{
OriginalAppBar = CurrentPage.BottomAppBar;
CurrentPage.BottomAppBar = MyCommandBar;
}
}
private void MyPickerFlyout_Closed(object sender, object e)
{
if (CurrentPage != null)
{
CurrentPage.BottomAppBar = OriginalAppBar;
}
}
}
Then you can use it in XAML like:
<Button Content="Show Picker">
<Button.Flyout>
<local:MyPickerFlyout Closed="PickerFlyout_Closed">
<TextBlock Margin="20" FontSize="30" Text="MyPickerFlyout Test" />
</local:MyPickerFlyout>
</Button.Flyout>
</Button>
And it looks like:

Silverlight Image Panning

I am working on silverlight application and I want to panning image like top, bottom, left, right how I can panning the image.
I had use the pixel shadering but I am not success of this.
thanks..
Have a look at this sample
You could also look at the Blend behavior for dragging.
This worked for me. User can preview an enlarged image using this window, and pan the image to the sections that is more relevant, e.g. the bottom part of the image.
To use the window:
BitmapImage BMP = /* resolve the bitmap */;
PreviewImageWindow.Execute(BMP);
The code (behind) for the window is shown below.
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;
namespace ITIS.Controls.LinearViewer.Windows {
public partial class PreviewImageWindow : ChildWindow {
/// <summary>See Execute</summary>
PreviewImageWindow() {
InitializeComponent();
}
private void OKButton_Click(object sender, RoutedEventArgs e) {
this.DialogResult = true;
}
private void CancelButton_Click(object sender, RoutedEventArgs e) {
this.DialogResult = false;
}
static public void Execute(BitmapImage imageSource) {
PreviewImageWindow Window = new PreviewImageWindow();
Window.Image.Source = imageSource;
/* don't allow the window to grow larger than the image */
Window.MaxWidth = imageSource.PixelWidth;
Window.MaxHeight = imageSource.PixelHeight;
Window.Show();
}
private void ChildWindow_KeyDown(object sender, KeyEventArgs e) {
if (e.Key == Key.Escape) {
DialogResult = false;
}
}
Point? _lastPoint;
bool _isMouseDown;
private void image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
((Image)sender).CaptureMouse();
_isMouseDown = true;
ShowCursor(e.GetPosition(Canvas));
_lastPoint = e.GetPosition((Image)sender);
}
private void image_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) {
((Image)sender).ReleaseMouseCapture();
_isMouseDown = false;
ShowCursor(e.GetPosition(Canvas));
_lastPoint = null;
}
private void image_MouseMove(object sender, MouseEventArgs e) {
if (_lastPoint != null) {
Image Image = (Image)sender;
Point CurrentPoint = e.GetPosition(Image);
double
XDelta = CurrentPoint.X - _lastPoint.Value.X,
YDelta = CurrentPoint.Y - _lastPoint.Value.Y;
_lastPoint = null;
if (XDelta != 0) {
double NewLeft = Canvas.GetLeft(Image) + XDelta;
if (NewLeft <= 0 && NewLeft + Image.ActualWidth >= Canvas.ActualWidth) {
Canvas.SetLeft(Image, NewLeft);
}
}
if (YDelta != 0) {
double NewTop = Canvas.GetTop(Image) + YDelta;
if (NewTop <= 0 && NewTop + Image.ActualHeight >= Canvas.ActualHeight) {
Canvas.SetTop(Image, NewTop);
}
}
_lastPoint = e.GetPosition(Image);
}
Point CanvasPoint = e.GetPosition(Canvas);
ShowCursor(CanvasPoint);
}
private void Canvas_Loaded(object sender, RoutedEventArgs e) {
TryDefaultImageToTop();
}
void TryDefaultImageToTop() {
if (Image == null || Canvas == null) { return; }
/* move the image up so we can focus on the road? user-friendly since we are most-likely going to look at the road, not the horizon or top - half */
if (!_initialized) {
_initialized = true;
Canvas.SetTop(Image, Canvas.ActualHeight - Image.ActualHeight);
Canvas.SetLeft(Image, (Canvas.ActualWidth - Image.ActualWidth) / 2);
}
}
bool _initialized;
private void image_Loaded(object sender, RoutedEventArgs e) {
TryDefaultImageToTop();
}
private void image_MouseEnter(object sender, MouseEventArgs e) {
imgOpenHand.Visibility = Visibility.Visible;
imgClosedHand.Visibility = Visibility.Collapsed;
ShowCursor(e.GetPosition(Canvas));
}
void ShowCursor(Point point) {
if (_isMouseDown) {
imgClosedHand.Visibility = Visibility.Visible;
imgOpenHand.Visibility = Visibility.Collapsed;
Canvas.SetLeft(imgClosedHand, point.X);
Canvas.SetTop(imgClosedHand, point.Y);
}
else {
imgClosedHand.Visibility = Visibility.Collapsed;
imgOpenHand.Visibility = Visibility.Visible;
Canvas.SetLeft(imgOpenHand, point.X);
Canvas.SetTop(imgOpenHand, point.Y);
}
}
private void image_MouseLeave(object sender, MouseEventArgs e) {
imgOpenHand.Visibility = Visibility.Collapsed;
imgClosedHand.Visibility = Visibility.Collapsed;
}
}
}
The XAML for the window is shown below:
<controls:ChildWindow
x:Class="ITIS.Controls.LinearViewer.Windows.PreviewImageWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
Background="#383838" Foreground="WhiteSmoke"
Title="Preview" Margin="50"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
KeyDown="ChildWindow_KeyDown"
>
<Grid x:Name="LayoutRoot" Margin="0" Cursor="None" IsHitTestVisible="True">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Canvas Cursor="None" IsHitTestVisible="True" x:Name="Canvas" Loaded="Canvas_Loaded">
<Image Source="{Binding ImageSource}" x:Name="Image"
Cursor="None" Loaded="image_Loaded"
MouseLeftButtonDown="image_MouseLeftButtonDown"
MouseLeftButtonUp="image_MouseLeftButtonUp"
MouseMove="image_MouseMove"
MouseEnter="image_MouseEnter"
MouseLeave="image_MouseLeave"
IsHitTestVisible="True"
/>
<Image Style="{StaticResource HandOpenImage}" x:Name="imgOpenHand"
Visibility="Collapsed" IsHitTestVisible="False"
/>
<Image Style="{StaticResource HandClosedImage}" x:Name="imgClosedHand"
Visibility="Collapsed" IsHitTestVisible="False"
/>
</Canvas>
</Grid>
A few CATCHES / COMMENTS about this code:
The namespace for this window is "ITIS.Controls.LinearViewer.Windows", please change the namespace to something more relevant in your system.
The normal cursor image is and when the mouse button is down, the image changes to
The styles for the images, which I have in a global application wide resource dictionary:
(OPEN image style)
<Style TargetType="Image" x:Key="HandOpenImage">
<Setter Property="Source" Value="/ITIS.Controls.LinearViewer.Silverlight;component/Images/HandOpen.png" />
<Setter Property="Width" Value="16" />
<Setter Property="Height" Value="16" />
</Style>
(CLOSED image style)
<Style TargetType="Image" x:Key="HandClosedImage">
<Setter Property="Source" Value="/ITIS.Controls.LinearViewer.Silverlight;component/Images/HandClosed.png" />
<Setter Property="Width" Value="13" />
<Setter Property="Height" Value="11" />
</Style>
This preview tries to START with focus on the bottom half of the image, NOT the top half.
Hope this helps. It took me a while to iron out a few irritations.