here's my dependency property declared :
public static void IsDesignModePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
WebBrowser browser = obj as WebBrowser;
if (browser != null)
{
Boolean designMode = (Boolean)args.NewValue;
if (designMode)
{
browser.LoadCompleted += (s, e) =>
{
var htmlDoc = (s as WebBrowser).Document as IHTMLDocument2;
htmlDoc.body.setAttribute("contenteditable", "true");
htmlDoc.designMode = "On";
};
}
else
{
browser.LoadCompleted += (s, e) =>
{
var htmlDoc = (s as WebBrowser).Document as IHTMLDocument2;
htmlDoc.body.setAttribute("contenteditable", "false");
htmlDoc.designMode = "Off";
};
}
}
}
here's my web browser control :
<WebBrowser viewmodel:BrowserBehavior.IsDesignMode="True" x:Name="webBrowser1" viewmodel:BrowserBehavior.Html="{Binding SelectedNode.ContentData.FileName, Converter={StaticResource converter}, Mode=OneWay}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Width="612"/>
i would like to programatically modify the content of the web browser , and disable modification by keyboard ; i mean with a button that act on selection !
How is that possible ?
i found how to disable keyboard while IsDesignMode ="true" :
<WebBrowser KeyDown="webBrowser1_KeyDown" ... />
in code behind :
private void webBrowser1_KeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
}
Still looking for the answer of the second part of my question !
Related
I tried to modify TextBox context menu/MenuFlyout using this code but it doesn't work (the additional menu Items don't appear and myFlyout always null) (UWP/C#)
private void Menu_Opening(object sender, object e)
{
MenuFlyout myFlyout = sender as MenuFlyout;
if (myFlyout != null && myFlyout.Target == TextBox)
{
MenuFlyoutSubItem searchWith = new MenuFlyoutSubItem();
searchWith.Icon = new SymbolIcon(Symbol.Find);
searchWith.Text = "Search With";
MenuFlyoutItem googles = new MenuFlyoutItem();
googles.Text = "Google";
googles.Click += Googles_Click;
searchWith.Items.Add(googles);
MenuFlyoutItem bings = new MenuFlyoutItem();
bings.Text = "Bing";
bings.Click += Bings_Click;
searchWith.Items.Add(bings);
myFlyout.Items.Add(searchWith);
}
}
private async void Googles_Click(object sender, RoutedEventArgs e)
{
if (TextBox.SelectedText != null)
{
var uri= new Uri(#"https://google.com/search?q=" + TextBox.SelectedText);
var success = await Launcher.LaunchUriAsync(uri);
}
}
private async void Bings_Click(object sender, RoutedEventArgs e)
{
if (TextBox.SelectedText != null)
{
var uri = new Uri(#"https://bing.com/search?q=" + TextBox.SelectedText);
var success = await Launcher.LaunchUriAsync(uri);
}
}
private void TextBox_Loaded(object sender, RoutedEventArgs e)
{
TextBox.SelectionFlyout.Opening += Menu_Opening;
TextBox.ContextFlyout.Opening += Menu_Opening;
}
private void TextBox_Unloaded(object sender, RoutedEventArgs e)
{
TextBox.SelectionFlyout.Opening -= Menu_Opening;
TextBox.ContextFlyout.Opening -= Menu_Opening;
}
<TextBox x:Name="TextBox" Loaded="TextBox_Loaded" Unloaded="TextBox_Unloaded"/>
The problem is that you have not give MenuFlyout instance to SelectionFlyout or ContextFlyout. Please refer the following code to add MenuFlyout.
<TextBox x:Name="TextBox" Loaded="TextBox_Loaded" Unloaded="TextBox_Unloaded">
<TextBox.ContextFlyout>
<MenuFlyout>
</MenuFlyout>
</TextBox.ContextFlyout>
</TextBox>
Update
The default type of SelectionFlyout is TextCommandBarFlyout, and it could not convert to MenuFlyout, if you don't want to replace the default one. you could add TextCommandBarFlyout like the following,
private void Menu_Opening(object sender, object e)
{
TextCommandBarFlyout myFlyout = sender as TextCommandBarFlyout;
if (myFlyout != null && myFlyout.Target == TextBox)
{
AppBarButton searchCommandBar = new AppBarButton() { Icon = new SymbolIcon(Symbol.Find), Label = "Search With" };
searchCommandBar.Click += SearchCommandBar_Click;
myFlyout.PrimaryCommands.Add(searchCommandBar);
}
}
private void SearchCommandBar_Click(object sender, RoutedEventArgs e)
{
}
I have a C# winform project with a webbrowser control. I'm loading an HTML page with images into the webbrowser. Each image has a different ID:
<img src="F:\Temp\file12948.jpg" id="12948" width="180px">
Is there a way to pass the ID into a variable when clicking on the image so I can use the ID in my code? The path to the image can also be used as I can extract the number from there.
I have already searched here there and everywhere for a solution but can't find anything related.
You can dynamically attach to image's onClick event.
public class TestForm : Form
{
WebBrowser _WebBrowser = null;
public TestForm()
{
_WebBrowser = new WebBrowser();
_WebBrowser.ScriptErrorsSuppressed = true;
_WebBrowser.Dock = DockStyle.Fill;
this.Controls.Add(_WebBrowser);
WebBrowserDocumentCompletedEventHandler Completed = null;
Completed = (s, e) =>
{
//add onclick event dynamically
foreach (var img in _WebBrowser.Document.GetElementsByTagName("img").OfType<HtmlElement>())
{
img.AttachEventHandler("onclick", (_, __) => OnClick(img));
}
_WebBrowser.DocumentCompleted -= Completed;
};
_WebBrowser.DocumentCompleted += Completed;
var imgurl = "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_120x44dp.png";
//_WebBrowser.Navigate("http://edition.cnn.com/2017/09/09/us/hurricane-irma-cuba-florida/index.html");
_WebBrowser.DocumentText = $"<html> <img src='{imgurl}' id=123 /> </html>";
}
void OnClick(HtmlElement img)
{
MessageBox.Show(img.GetAttribute("id"));
}
}
On simple way would be to use browser navigation. When clicking you can navigate to a special URL, then you handle the Navigating event and if the url is the special url you cancel the navigation and handle the data.
public MainWindow()
{
InitializeComponent();
br.NavigateToString(#"<img src=""F:\Temp\file12948.jpg"" id=""12948"" width=""180px"" >");
br.Navigating += this.Br_Navigating;
}
private void Br_Navigating(object sender, NavigatingCancelEventArgs e)
{
if(e.Uri.Host == "messages")
{
MessageBox.Show(e.Uri.Query);
e.Cancel = true;
}
}
This works if you have some control over the HTML. You could also set the URL from JS if you don't want to add the anchor.
Edit
The above version is for a WPF application. The winforms version is as follows:
public Form1()
{
InitializeComponent();
webBrowser1.DocumentText = #"<img src=""F:\Temp\file12948.jpg"" id=""12948"" width=""180px"" >";
webBrowser1.Navigating += this.webBrowser1_Navigating;
}
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
if (e.Url.Host == "messages")
{
MessageBox.Show(e.Url.Query);
e.Cancel = true;
}
}
I have a web browser in WPF
<WebBrowser x:Name="WebBrowserControl" Width="1000" Height="600" Source="https://www.1.com" cal:Message.Attach="[Event LoadCompleted]=[Action LoadCompleted($eventArgs)]"/>
It loads the www.1.com and when i click a button on 1.com it jump to http://2.com
I listen to loadCompleted event
public void LoadCompleted(NavigationEventArgs e)
{
if (e.Uri.AbsoluteUri == "https://www.2.com")
{
//Here i want to get WebBrowserControl.Document as mshtml.HTMLDocument;
MessageBox.Show("Completed loading the page");
}
}
I want to get 2.com htmlDocument. is there a way to achieve that. I achieve that in not viewmodel way.
private void WebBrowserControl_LoadCompleted(object sender, NavigationEventArgs e)
{
string[] tags = new string[]{};
if (e.Uri.OriginalString == "https://www.2.com")
{
MessageBox.Show("here");
var document = WebBrowserControl.Document as mshtml.HTMLDocument;
}
}
I did something like this
//view
cal:Message.Attach="[Event LoadCompleted]=[Action LoadCompleted(WebBrowserControl.Document,$eventArgs)]"
//ViewModel
public void LoadCompleted(mshtml.HTMLDocument x ,NavigationEventArgs e)
{
//it calls this method but the x is null
}
<WebBrowser x:Name="WebBrowserControl" Width="1000" Height="600" Source="https://www.1.com" cal:Message.Attach="[Event LoadCompleted]=[Action LoadCompleted($source,$eventArgs)]"/>
public void LoadCompleted(object sender ,NavigationEventArgs e)
{
WebBrowser x = (WebBrowser)sender;
var document = x.Document as mshtml.HTMLDocument;
}
I am building a Universal App and I think I have found a bug in the Windows Phone 8.1 PopupMenu control. I have been able to reproduce it with a small piece of code. It works fine on Windows 8 but not on Windows Phone 8.1.
Whenever I create a PopupMenu from within a button click it doesn't return from ShowFromSelectionAsync() when there is a background task running ? Why ?
The same code works on Windows 8.
I my application a lot of background work is being done, so the control doesn't work correctly on Phone anymore. Any suggestions how to fix this ?
I have a MainPage.xaml:
<Page
x:Class="PopupMenuBugPhone.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:PopupMenuBugPhone"
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}">
<StackPanel>
<Button Content="Test Bug" Click="Button_Click" />
</StackPanel>
</Grid>
</Page>
MainPage.xaml.cs:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
var frameworkElement = sender as FrameworkElement;
var task = SimulateBackgroundWork(); // COMMENT THIS TO MAKE IT WORK ON PHONE!!!
var menu = new PopupMenu();
var сmdOption1 = new UICommand("Option1");
var cmdOption2 = new UICommand("Option2");
menu.Commands.Add(сmdOption1);
menu.Commands.Add(cmdOption2);
// We don't want to obscure content, so pass in a rectangle representing the sender of the context menu event.
var chosenCommand = await menu.ShowForSelectionAsync(frameworkElement.GetElementRect());
if (chosenCommand == null) // The command is null if no command was invoked.
{
await new MessageDialog("No choice").ShowAsync();
}
else
{
await new MessageDialog("Choice: " + chosenCommand.Label).ShowAsync();
}
await task; // COMMENT THIS TO MAKE IT WORK ON PHONE!!!
}
private Task SimulateBackgroundWork()
{
var t = Task.Run(() =>
{
var dt = DateTime.Now;
// Do some dummy processing loop
while (DateTime.Now < dt.AddSeconds(300))
{
;
}
});
return t;
}
}
How about using a MenuFlyout?
Let's say you defined it in code-behind of the page, along with the TaskCompletionSource to wrap it to make showing awaitable:
MenuFlyout flyout = new MenuFlyout();
TaskCompletionSource<string> tcs;
Then on button click you could do this:
private async void Button_Click(object sender, RoutedEventArgs e)
{
var frameworkElement = sender as FrameworkElement;
var task = SimulateBackgroundWork();
flyout.Closed += flyout_Closed;
var mf1 = new MenuFlyoutItem { Text = "Option1" };
var mf2 = new MenuFlyoutItem { Text = "Option2" };
mf1.Click += mf_Click;
mf2.Click += mf_Click;
flyout.Items.Clear();
flyout.Items.Add(mf1);
flyout.Items.Add(mf2);
await ShowMenuFlyout(sender as FrameworkElement);
await task;
}
ShowMenuFlyout is awaitable and implemented like this:
public Task<string> ShowMenuFlyout(FrameworkElement sender)
{
tcs = new TaskCompletionSource<string>();
flyout.ShowAt(sender as FrameworkElement);
return tcs.Task;
}
And event handlers would simply do this:
async void mf_Click(object sender, RoutedEventArgs e)
{
flyout.Closed -= flyout_Closed;
await new MessageDialog("Choice: " + (sender as MenuFlyoutItem).Text).ShowAsync();
tcs.SetResult((sender as MenuFlyoutItem).Text);
}
async void flyout_Closed(object sender, object e)
{
flyout.Closed -= flyout_Closed;
await new MessageDialog("No choice").ShowAsync();
tcs.SetResult("No choice");
}
This works on both platforms. Of course, this is just proof of concept, you might want a null check here or there, but it works.
I have a Windows phone application which gets a list of photos URLs from a SQL database depending what it uploaded.
The issue i have is users can add their own photos to that list but it does not refresh the list on the page so i added a refresh to re run the code but it still does not run.
Well the code runs but does not update the list box.
//get/clean these strings
int parkID = 0;
string parkName = string.Empty;
public photos()
{
InitializeComponent();
BuildLocalizedApplicationBar();
}
private void ThemeParkPhotos_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
try
{
//No errors have been passed now need to take this file and parse it
//Its in XML format
XDocument xdox = XDocument.Parse(e.Result);
//need a list for them to be put in to
List<Photos> themeparkPhoto = new List<Photos>();
themeparkPhoto.Clear();
XNamespace ns = "http://schemas.datacontract.org/2004/07/WCFServiceWebRole1";
//Now need to get every element and add it to the list
foreach (XElement item in xdox.Descendants(ns + "Photos"))
{
Photos content = new Photos();
content.ID = Convert.ToInt32(item.Element(ns + "ID").Value);
content.PhotoURL = Convert.ToString(item.Element(ns + "PhotoURL").Value);
//content.ID = Convert.ToInt32(item.Element(ns + "id").Value);
//content.ThemeParkName = item.Element(ns + "name").Value.ToString();
themeparkPhoto.Add(content);
}
ThemeParkPhoto.ItemsSource = null;
ThemeParkPhoto.ItemsSource = themeparkPhoto.ToList();
//Delete all the stuff
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
else
{
//There an Error
}
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
//This is to get the data that was passed from the home screen to which song to use!
base.OnNavigatedTo(e);
if ((NavigationContext.QueryString["pID"] == string.Empty) || (NavigationContext.QueryString["pName"] == string.Empty))
{
//if not show message box.
MessageBox.Show("Empty Vaules have been sent, Please got back and try again");
}
else
{
parkID = Convert.ToInt32(NavigationContext.QueryString["pID"]);
parkName = NavigationContext.QueryString["pName"].ToString();
PageName.Text = parkName;
GetThemeParkPhotos();
}
}
public void GetThemeParkPhotos()
{
WebClient ThemeParkPhotos = new WebClient();
ThemeParkPhotos.DownloadStringCompleted += ThemeParkPhotos_DownloadStringCompleted;
ThemeParkPhotos.DownloadStringAsync(new Uri("HIDDEDURL/viewphotos?format=xml&themeparkid=" + parkID));
//MessageBox.Show("Test if this works"+parkID);
}
private void BuildLocalizedApplicationBar()
{
ApplicationBar = new ApplicationBar();
ApplicationBar.Mode = ApplicationBarMode.Default;
ApplicationBar.Opacity = 1.0;
ApplicationBar.IsVisible = true;
ApplicationBar.IsMenuEnabled = true;
ApplicationBarIconButton AddButton = new ApplicationBarIconButton();
AddButton.IconUri = new Uri("/Images/add.png", UriKind.Relative);
AddButton.Text = "Add Photo";
ApplicationBar.Buttons.Add(AddButton);
AddButton.Click +=AddButton_Click;
//Dont add refresh button as it does not work at this time :(
ApplicationBarIconButton RefreshButton = new ApplicationBarIconButton();
RefreshButton.IconUri = new Uri("/Images/refresh.png", UriKind.Relative);
RefreshButton.Text = "Refresh";
ApplicationBar.Buttons.Add(RefreshButton);
RefreshButton.Click += RefreshButton_Click;
}
private void RefreshButton_Click(object sender, EventArgs e)
{
GetThemeParkPhotos();
}
private void AddButton_Click(object sender, EventArgs e)
{
//need to send them to add a photo page with details.
NavigationService.Navigate(new Uri("/TakePhoto.xaml?pID=" + parkID + "&pName=" + parkName, UriKind.Relative));
}
Here the Code for the ListBox
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox Height="559" HorizontalAlignment="Left" Margin="6,20,0,0" x:Name="ThemeParkPhoto" VerticalAlignment="Top" Width="444" FontSize="30" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock x:Name="ID" Text="{Binding ID}"></TextBlock>
<Image x:Name="PhotoURL" Source="{Binding PhotoURL}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
I have removed the URL to save the API, That code does run and fill it but why does it not refresh the List Box correctly?
Many Thanks
Thank to being sent here : C# WebClient disable cache
Turns out that Windows phone web client caches the file meaning it never download it again until the app is refreshed. By using a random number generator and adding it to the then of the URL it will always download the file allowing for a refresh.