Is there any way to query the state of an IE plugin (Adobe Reader)? I have a situation where we present many multi-page reports to users through an embedded browser (the preferred pattern based on my research) hosted by a tab page. When the user navigates away from the report, usually to modify the data, they return to re-initialized Adobe Reader. This means their place was lost and expanded bookmark nodes have been collapsed.
Below is a simplified code snippet which I hope full expresses the nature of my problem.
Public partial class ReportView : UserControl
{
private System.Windows.Forms.WebBrowser webBrowser;
private MyNamespace.ReportGenerator reportGen;
private String currentPDFtempPath;
public ReportView()
{
InitializeComponent();
this.Leave += (o, e) => { /*how can I save current place in pdf?*/ };
this.Enter += (o, e) => { /*return user last place in large pdf*/ };
}
public void ViewReport(string reportName)
{
currentPDFtempPath = reportGen.GetReport(reportName);
webBrowser.Navigate(currentPDFtempPath);
}
private void RefreshReport()
{
webBrowser.Navigate(currentPDFtempPath); /*reinitializes Adobe Reader*/
}
}
public class ReportController
{
private DataModel model;
private ReportView view;
ReportController(DataModel m, ReportView v)
{
this.model = m;
this.view = v;
model.Changed += (o, e) => { view.RefreshReport(); }
}
}
If your user base has standardized to one version of Acrobat or continuously updates to the latest and greatest Acrobat, an alternate solution is to eliminate the webbrowser control and add a reference to the AcroPDF/AxAcroPDF library/active x control, which works from a windows form. I have used this in my company for the past 6 years and it has worked flawlessly.
Related
I have created a PowerPoint VSTO Addin with a custom Task pane - and a ribbon where a toggle button defines the display / hide Status of the custom Task pane. Basis for this was the Microsoft Walkthrough information for custom Task pane and synchronizing the Ribbon with the Task pane.
So fare everything works fine with the first PowerPoint window. I'm able to show the Task pane in the second and third PowerPoint window, but the toggle button on the ribbon only reacts to the last opened / created PowerPoint window and not to the Task pane displayed / hidded in the active PowerPoint window.
I've found another thread which explains exactly the same Problem here:
C# VSTO-Powerpoint-TaskPanes in separate windows.
But I don't understand the answer neither I don't know how to implement a PowerPoint Inspector Wrapper.
I'm new in C# and just getting a keyword like "Inspector Wrapper" is to less for me. I already spend hours in searching the net but wasn't successfull till now.
Is there a chance to get a COMPLETE code example for PowerPoint how this works, what has to be done?
Code added:
I took the code from the General walkthrough: https://msdn.microsoft.com/en-us/library/bb608590.aspx and changed it with an Event for new presentations:
The code for the ThisAddIn.cs is as follow:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using Office = Microsoft.Office.Core;
namespace PowerPointAddIn1
{
public partial class ThisAddIn
{
private TaskPaneControl taskPaneControl1;
private Microsoft.Office.Tools.CustomTaskPane taskPaneValue;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
this.Application.AfterNewPresentation += new Microsoft.Office.Interop.PowerPoint.EApplication_AfterNewPresentationEventHandler(NewPresentation);
//taskPaneControl1 = new TaskPaneControl();
//taskPaneValue = this.CustomTaskPanes.Add( taskPaneControl1, "MyCustomTaskPane");
//taskPaneValue.VisibleChanged += new EventHandler(taskPaneValue_VisibleChanged);
}
void NewPresentation(Microsoft.Office.Interop.PowerPoint.Presentation oPres)
{
PowerPoint.Application app = this.Application;
PowerPoint.DocumentWindow docWin = null;
foreach (PowerPoint.DocumentWindow win in Globals.ThisAddIn.Application.Windows)
{
if (win.Presentation.Name == app.ActivePresentation.Name)
{
docWin = win;
}
}
this.taskPaneControl1 = new TaskPaneControl();
this.taskPaneValue = this.CustomTaskPanes.Add(taskPaneControl1, "MyCustomTaskPane", docWin);
this.taskPaneValue.VisibleChanged += new EventHandler(taskPaneValue_VisibleChanged);
}
private void taskPaneValue_VisibleChanged(object sender, System.EventArgs e)
{
Globals.Ribbons.ManageTaskPaneRibbon.toggleButton1.Checked =
taskPaneValue.Visible;
}
public Microsoft.Office.Tools.CustomTaskPane TaskPane
{
get
{
return taskPaneValue;
}
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
}
#region VSTO generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
}
I remember the learning curve oh so well. Here's a sample that I believe addresses your issue. You need to link the task pane to the document. I relied on the naming scheme for new documents here, but a DocumentVariable would be a much better choice (they are discarded at the end of the current session). Add a variable to the presentation, store the task pane id in the control, and compare them to get the right task pane.
You need an XML ribbon (could probably use a Ribbon Designer but those are not as good). I removed some of the boilerplate and irrelevant code from this.
ThisAddIn.cs:
namespace PowerPointAddIn1
{
public partial class ThisAddIn
{
public static int counter = 0;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
this.Application.AfterNewPresentation += Application_AfterNewPresentation;
}
private void Application_AfterNewPresentation(PowerPoint.Presentation Pres)
{
int count = ++counter;
UserControl1 uc = new UserControl1("task pane " + count);
CustomTaskPane ctp = CustomTaskPanes.Add(uc, "custom task pane " + count);
ctp.Visible = true;
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
}
protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject()
{
return new Ribbon1();
}
}
}
Ribbon1.cs:
namespace PowerPointAddIn1
{
[ComVisible(true)]
public class Ribbon1 : Office.IRibbonExtensibility
{
private Office.IRibbonUI ribbon;
public Ribbon1()
{
}
public void toggleTaskPane(Office.IRibbonControl control, bool enabled)
{
var CTPs = Globals.ThisAddIn.CustomTaskPanes;
var pres = Globals.ThisAddIn.Application.ActivePresentation;
foreach (var x in CTPs)
{
if (pres.Name.EndsWith(x.Title.Replace("custom task pane ", "")))
{
x.Visible = enabled;
}
}
}
public bool isPressed(Office.IRibbonControl control)
{
var CTPs = Globals.ThisAddIn.CustomTaskPanes;
var pres = Globals.ThisAddIn.Application.ActivePresentation;
foreach (var x in CTPs)
{
if (pres.Name.EndsWith(x.Title.Replace("custom task pane ", "")))
{
return x.Visible;
}
}
return false;
}
}
}
Ribbon1.xml:
<?xml version="1.0" encoding="UTF-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="Ribbon_Load">
<ribbon>
<tabs>
<tab idMso="TabAddIns">
<group id="MyGroup"
label="My Group">
<checkBox id="mycheckbox" label="show task pane" onAction="toggleTaskPane" getPressed="isPressed" />
</group>
</tab>
</tabs>
</ribbon>
</customUI>
UsreControl1.cs (just has a label on it):
namespace PowerPointAddIn1
{
public partial class UserControl1 : UserControl
{
public UserControl1(string labelValue)
{
InitializeComponent();
label1.Text = labelValue;
}
}
}
I just want to share my results which works now for me (Thanks to Chris who gave me some valuable inputs). I do have a customtaskpane management which works for each presentation. The only Thing which is not yet implemented is if a user opens the document in a separate window (View / New Window). This one I don't know how to manage.
As fare as I can test it this works now.
here is the link to the whole solution:
https://happypc-my.sharepoint.com/personal/roger_heckly_happy-pc_ch/_layouts/15/guestaccess.aspx?docid=0426d40dc5df74d66ba42a3b928111ce8&authkey=Aa6yX6QWUnqXp1jcUfGveL8
Please be Aware - I'm beginner - so if you have feedback / inputs please let me know. For sure, some code could be written easier etc.
I am trying to use cefshar browser in C# winforms and need to know how I know when page completely loaded and how I can get browser document and get html elements,
I just Initialize the browser and don't know what I should do next:
public Form1()
{
InitializeComponent();
Cef.Initialize(new CefSettings());
browser = new ChromiumWebBrowser("http://google.com");
BrowserContainer.Controls.Add(browser);
browser.Dock = DockStyle.Fill;
}
CefSharp has a LoadingStateChanged event with LoadingStateChangedArgs.
LoadingStateChangedArgs has a property called IsLoading which indicates if the page is still loading.
You should be able to subscribe to it like this:
browser.LoadingStateChanged += OnLoadingStateChanged;
The method would look like this:
private void OnLoadingStateChanged(object sender, LoadingStateChangedEventArgs args)
{
if (!args.IsLoading)
{
// Page has finished loading, do whatever you want here
}
}
I believe you can get the page source like this:
string HTML = await browser.GetSourceAsync();
You'd probably need to get to grips with something like HtmlAgility to parse it, I'm not going to cover that as it's off topic.
I ended up using:
using CefSharp;
wbAuthorization.AddressChanged += OnAddressChanged;
and
private void OnAddressChanged(
object s,
AddressChangedEventArgs e)
{
if (e.Address.StartsWith(EndUri))
{
ResultUri = new Uri(e.Address);
this.DialogResult = DialogResult.OK;
}
}
EndUri is the final page I want to examine and ResultUri contains a string I want to extract later. Just some example code from a larger class.
I have been trying to load a default user control every time any other user control on the same panel is closed by the user. I have a panel named MainContainer and when the main form loads I am calling the following method to load that default user control named welcome.
public void AddUserControlWelcome()
{
MainContainer.Controls.Clear();
welcome.Dock = DockStyle.Fill;
MainContainer.Controls.Add(welcome);
}
I have a menustrip button which calls the following method,
private void sellItemsToolStripMenuItem_Click(object sender, EventArgs e)
{
AddUserControlSellManager();
}
And it is defined as,
public void AddUserControlSellManager()
{
MainContainer.Controls.Clear();
sellManager.Dock = DockStyle.Fill;
MainContainer.Controls.Add(sellManager);
}
So, there is a button on sellManager user control which actually closes sellManager. And after that I am invoking AddUserControlWelcome() again from MainContainer_ControlRemoved(object sender, ControlEventArgs e) but the application is crashing and I don't know why.
I think, it is clear why you having this issue. MainContainer_ControlRemoved called not only when you remove your "sell" but "welcome" too. So, the culprit I believe is the fact that you do add control on such event as MainContainer_ControlRemoved, which you shouldn't do. As good as .Net is, sometimes you have to stay away from using certain events for certain purposes , or you run into issues.
Try to do something like this. Considering that your surface can host only one control at the time
class SurfaceManager
{
private Control _defaultCtrl;
private bool _currentDefault;
private Control _surface;
void SurfaceManager(Control _surface, Control defaultCtrl)
{
_surface = surface;
_defaultCtrl = defaultCtrl;
_surface = surface.Controls.Add(_defaultCtrl);
_currentDefault = true;
}
public Control Add(Control ctrl)
{
Control c = null; // Returning removed control so you can do something else with it
if (_surface.Controls.Count > 0)
{
if (!_currentDefault)
c = _surface.Controls[0];
_surface.Controls.Clear();
}
_surface = surface.Controls.Add(ctrl);
_currentDefault = false;
Return c;
}
public Control Remove()
{
if (_currentDefault) Return // Current is default - do nothing
Control c = null; // Returning removed control so you can do something else with it
if (_surface.Controls.Count > 0)
{
c = _surface.Controls[0];
_surface.Controls.Clear();
}
_surface = surface.Controls.Add(_defaultCtrl);
_currentDefault = true;
Return c;
}
}
Now, in your class create instance of this manager and use Add or Remove. Remove will automatically bring on the Welcome screen
I'm developing a Windows Phone app that uses the older WP7 Microsoft.Phone.Controls.Maps.Map / Bing Map control.
The map tiles are being served up from a local source so the app doesn't not need a network connection to work. Unfortunately the map control insists on showing an "Unable to contact Server. Please try again later." message over the map when offline.
Does anyone know of a method to remove / hide this message?
Just in case you're curious - I'm developing a WP8 app but using the depreciated WP7 Bing map control as the new WP8 map control provides no method for replacing the Bing base map.
i think this may suits you better:
void YourPage_Loaded(object sender, RoutedEventArgs e)
{
m_Map.ZoomLevel = 11;
m_Map.LayoutUpdated += m_Map_LayoutUpdated;
}
void m_Map_LayoutUpdated(object sender, EventArgs e)
{
if (!isRemoved)
{
RemoveOverlayTextBlock();
}
}
void RemoveOverlayTextBlock()
{
var textBlock = m_Map.DescendantsAndSelf.OfType<TextBlock>()
.SingleOrDefault(d => d.Text.Contains("Invalid Credentials") ||
d.Text.Contains("Unable to contact Server"));
if (textBlock != null)
{
var parentBorder = textBlock.Parent as Border;
if (parentBorder != null)
{
parentBorder.Visibility = Visibility.Collapsed;
}
isRemoved = true;
}
}
You have to include a class LinqToVisualTree witch can be downloaded from here.
And here is the original post
You can either handle the LoadingError event per instance or extend the Map control yourself as described in this post. You can then remove the layer than contains the error message so that it's not shown to the user.
public partial class CachedMap : Map
{
public CachedMap() : base()
{
base.LoadingError += (s, e) =>
{
base.RootLayer.Children.RemoveAt(5);
};
}
}
I know it's a very old thread, but anyways...
You can listen for LoadingError event as suggested #keyboardP, search for LoadingErrorMessage control in visual tree and simply hide it.
Map.LoadingError += MapOnLoadingError;
private void MapOnLoadingError(object sender, LoadingErrorEventArgs e)
{
var errorMessage = Map.FindChildOfType<LoadingErrorMessage>();
errorMessage.Visibility = Visibility.Collapsed;
}
I'm developing a Windows 8 store application in c#/xaml. The windows store guidelines say that when a user changes a settings, the application should reflect that change immediately. I need help figuring out how to make this happen.
Here are some details about my setup.
I've created a custom control called OptionsView:
public partial class OptionsView : UserControl
{
public OptionsView()
{
this.InitializeComponent();
}
private void cmbEarliestYear_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ApplicationDataContainer roamingSettings = Windows.Storage.ApplicationData.Current.RoamingSettings;
roamingSettings.Containers["appOptions"].Values["earliestYear"] = cmbEarliestYear.SelectedValue.ToString();
}
}
In my App.xaml.cs class, I'm using a SettingsFlyout from the Callisto library to display the custom options control when the user clicks on the Options link:
protected override void OnWindowCreated(WindowCreatedEventArgs args)
{
base.OnWindowCreated(args);
SettingsPane.GetForCurrentView().CommandsRequested += onCommandsRequested;
}
void onCommandsRequested(SettingsPane settingsPane, SettingsPaneCommandsRequestedEventArgs eventArgs)
{
UICommandInvokedHandler optionsHandler = new UICommandInvokedHandler(onOptionsClick);
SettingsCommand optionsCommand = new SettingsCommand("options", "Options", optionsHandler);
eventArgs.Request.ApplicationCommands.Add(optionsCommand);
}
void onOptionsClick(IUICommand command)
{
SettingsFlyout settings = new SettingsFlyout();
settings.FlyoutWidth = SettingsFlyout.SettingsFlyoutWidth.Narrow;
settings.HeaderText = "Options";
settings.Content = new OptionsView();
settings.IsOpen = true;
}
I have a page in my application called CreateTripPage. There's a combobox on that page that allows the user to change the year of the trip. The earliest year in that combobox needs to change based on the value set by the user in Options. So, when the user changes the value of cmbEarliestYear in the OptionsView while the CreateTripPage is open, I need an event to fire. I can't figure out how to fire/subscribe to the needed event.
Any help would be appreciated.
Here is a simple example of similar behaviour I implemented. Cineworld app can be used to view details about cinemas / movies / in UK and Ireland.
Options page within Settings Pane, allows region to be selected / modified. This meant that my app needs to cater for region modification while it is running.
What I tend to do is this:
1) Have a config class that defines properties and persists those values.
2) The config class exposes a property
public static event Action RegionChanged = delegate { };
3) In setter of the Region property fire the event.
if (RegionChanged != null)
RegionChanged();
4) Now in MainPage.xaml.cs or the main app entry point.
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
Config.RegionChanged -= Config_RegionChanged;
Config.RegionChanged += Config_RegionChanged;
// do whatever else you need to do (initial data load)
base.OnNavigatedTo(e);
}
async void Config_RegionChanged()
{
bLoaded = false;
this.GoHome(this, new RoutedEventArgs());
}
That's it really.