Add WebView2 control to tabitem and navigate to website - c#

I'm fiddling around with Microsofts WebView2 control. I created a simple wpf application, nothing fancy: Just MainWindow with a tabcontrol. Every tab has it's own user data directory.
Then I added a method to instantiate a tabitem and a webview and then add that control to the tabcontrol in MainWindow.
What I have so far - which is working (but...):
private async void AddTab(string serviceName, string serviceUrl)
{
TabItem tabItem = new TabItem();
tabItem.Name = serviceName;
tabItem.Header = serviceName;
myTabControl.Items.Add(tabItem);
// Create a unique user data directory for this tab
// and keep it "portable", a.k.a. in the programm directory
string userDataDirectory = System.IO.Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + "\\Sessions\\" + serviceName;
// Create a new WebView2 control and pass custom user data directory
WebView2 webView = new WebView2() { CreationProperties = new CoreWebView2CreationProperties() { UserDataFolder = userDataDirectory } };
// set the source address
webView.Source = new Uri(serviceUrl);
// add webview to tab content
tabItem.Content = webView;
// Initialize the WebView2 control
await webView.EnsureCoreWebView2Async();
}
This works as intended. But as it is now, the webview content is only loaded when I click on the tab. I'm not sure how to make the tabs load in the background, so that when I click on the tab, the website is already loaded.
I found one example on stackoverflow, but it is too complex for what I want to accomplish.
My experiment with a Task brought me into the crazy world of not being able to access my thread again. Such code is way over my head (for now). I'm still learning.

I would try defining the tabitems in xaml.
The tabcontrol is an itemscontrol. I would usually bind the itemssource to a collection of viewmodels and template those out into ui. You only get whichever one of those items is selected instantiated if you bind the items like that. Defining tabitems in xaml seems to mean they're all instantiated. It's noticeably slower.
You can add other tabs afterwards in code if you wanted. But I'd check what happens with some defined in xaml first.
Another thing you could try is hidden webview2 controls in the main view. Navigate to these fixed url immediately the window renders.
Move them out the window and into your tabitem on selecting that tab, set isvisible true. Then you're just incurring rendering.
Btw
The webview2 is a wrapper around a chromium edge browser. It displays some odd behaviour like it can overflow parent containers.

Related

Cloning tabs in Tab Control on button click in Winforms

so I have a Homepage on one of the TabPages on winform TabControl. I have a button, that adds a new tab using this Tabs.TabPages.Add("Homepage");
But TabPages.Add() just adds a new blank page, how would i clone my HomePage on the new tab? For instance, if my homepage has a button "Click me", when i open a new tab, I want it to have the same button "Click me" linked to the same event "ClickMe_click". Like a Chrome Tab control. I couldn't find any event or method built in for TabControl on msdn, unless i missed it.
Any help or hint or suggestion would be appreciated. Thanks.
You can't clone a tabpage so easily. One can try but the recommended way is:
Create a UserControl and add all the controls you want on your page. Make it Dock=Fill and add any code that connects the controls. You can layout as freely as you would in a form or a tabpage..
Whenever you want another page of this type, add a new tabpage and add an instance of the UserControl to its Controls collection.
Note: All controls on your UserControl by default are private. This is not really different from placing them on the tabpage directly. But now they are private members of the UC class, so your form and its code can't access them.
Looks like a problem when you're new to it. But if you look at it right, it is a good oportunity to create a leaner & cleaner interface.
Solution 1: Change the control modifiers to public as needed
Solution 2: Add properties to expose those data you really want to expose.
Also note: You can do all layout but can do so only in the UC designer. After adding to a form or tabpage there will be no embedded designer..

How to remove Windows border from WPF UserControl?

To preface this question, I am working on coding the back end of an application whose UI was put together by someone else (I believe using Blend). The application consists of a series of "Screens," whose root element in XAML is "UserControl". There is no use of the "Window" tag anywhere in the source.
What I want to do is remove the Windows border that is added to the outside edge of the application when I run the program. The border currently consists of forward/backward buttons like a web browser, and an X button to close.
All I can find from searches are instructions to add
WindowStyle="None"
to the
<Window>
element. But of course, I don't have one of those, and WindowStyle is not a property of UserControl. Anyone know how to accomplish this with UserControl root elements?
Edit: The StartupUri for the application is
this.StartupUri = new Uri(#"pack://application:,,,/WpfPrototype1.Screens;Component/Screen_1.xaml");
the file it points to does not have a Window tag.
Based on the comments above it seems your MainWindow is created dynamically somewhere, however you can use the Application class to get the applications MainWindow.
var mainWindow = Application.Current.MainWindow;
And you can then set your border style from there
Example:
private void RemoveBorder()
{
var mainWindow = Application.Current.MainWindow;
if (mainWindow != null)//should never be
{
mainWindow.WindowStyle = System.Windows.WindowStyle.None; // removes top bar (icon, title, close buttons etc)
mainWindow.AllowsTransparency = true; //removes the border around the outside
}
}

"Clear" window to make room for new user controls?

I'm usually working with Windows Forms Applications, but I'm currently needing Windows Presentation Foundation for design purposes.
What I am needing to do is clear out the current open window and fill it with new user controls as though a new window has been opened. In short, open a new window without actually opening a new window, similar to navigating to a new page in a web browser. (Still the same window open in the Taskbar, no extras.)
I was unsure if there was a specific class or control that made this easy to do. If someone could enlighten me on the way to do this in WPF, I would be very pleased.
Thanks.
There are a number of possible ways - here are a few that come to mind:
Navigation
In WPF, you can actually navigate to different xaml pages. In this scenario, you would define a number of pages that a main page could navigate to.
http://msdn.microsoft.com/en-us/library/ms750478.aspx
Programmatic
You can do it the old school way and just clear out all of the controls in a window. For example (in the context of a window):
StackPanel stackPanel = new StackPanel();
stackPanel.Children.Add(new MyUserControl1());
stackPanel.Children.Add(new MyUserControl2());
this.Content = stackPanel;

WPF TabControl - Cannot programmatically select tabs

I have a user interface with a TabControl that initially displays a start page. Other items can be added to it by double-clicking on content in, for example, a DataGrid. New tabs should be selected when they are created. If the document corresponding to the item in the grid is already open, then the existing tab for that document should be opened rather than creating a new one.
I know that I should be able to programmatically select a tab by setting the TabControl's SelectedItem or SelectedIndex properties. However, the desired tab never actually activates. If I set one and then inspect the TabControl's state in the debugger, then both fields seem to update properly. However, after I continue execution, I see that the selected tab remains unchanged in the UI, and if I pause and inspect the TabControl's state again I see that the SelectedItem and SelectedIndex have returned to their previous values. Selecting a tab by clicking on it in the UI, on the other hand, works just fine.
Here's the declaration for the TabControl:
<TabControl x:Name="Tabs" >
<TabItem x:Name="StartPageTab" Header="Start Page" DataContext="{Binding Path=StartPageViewModel}">
...
</TabItem>
</TabControl>
And the code for adding and selecting tabs:
private void _SelectTab(MyViewModel model)
{
TabItem tab;
if (_TryFindTab(model, out tab)) Tabs.SelectedItem = tab;
}
private bool _TryFindTab(MyViewModel target, out TabItem tab)
{
foreach (TabItem item in Tabs.Items)
{
MyViewModel model = item.DataContext as MyViewModel;
if (model != null && model.Equals(target))
{
tab = item;
return true;
}
}
tab = null;
return false;
}
private void _AddTab(MyViewModel model)
{
TabItem tab = new TabItem { DataContext = model, Content = new MyView() };
Binding bind = new Binding { Source = model, Path = new PropertyPath("Name") };
tab.SetBinding(TabItem.HeaderProperty, bind);
Tabs.Items.Add(tab);
Tabs.SelectedItem = tab;
}
It turned out to be related to something I conveniently omitted from the original problem description:
The DataGrid in question was in the content for StartPageTab. I was handling double-clicks on that DataGrid by capturing its MouseDoubleClick event, searching the visual tree to find what DataGridRow was double-clicked (if any), and then raising an event that would eventually be captured by the main window, which would respond by calling either _SelectTab or _AddTab, depending on whether the document in question was already open.
At which point, the call stack would unroll and get back to that MouseDoubleClick event handler. In that handler, I forgot to set the MouseButtonEventArgs's Handled property to true. So WPF kept searching for someone else to handle that click event - and the element that it eventually found would respond by asking for focus, which in turn meant that the original tab needed to get focus back.
Adding e.Handled = true; stopped that whole mess in its tracks, so the new tab could stay selected.
You could try using tab.focus()
I have tabs in my application and this is a quick way to make your selected tab visible.
Have you tried binding to TabItem.IsSelected and updating that in you view model?
In an older C# app I had, using page controls, I was able to force the page active by telling the tab control object to select the tab...
MyTabControlWithMultiplePages.SelectTab(PageIWantShown);

Sizing issues while adding a .Net UserControl to a TabPage

I have a complex Windows Forms GUI program that has a lot of automated control generation and manipulation. One thing that I need to be able to do is add a custom UserControl to a newly instatiated TabPage. However, when my code does this I get automatic resizing events that cause the formatting to get ugly. Without detailing all of the different Containers that could possibly be involved, the basic issue is this:
At a certain point in the code I create a new tab page:
TabPage tempTabPage = new TabPage("A New Tab Page");
Then I set it to a certain size that I want it to maintain:
tempTabPage.Width = 1008;
tempTabPage.Height = 621;
Then I add it to a TabControl:
tabControl.TabPages.Add(tempTabPage);
Then I create a user control that I want to appear in the newly added TabPage:
CustomView customView = new CustomView("A new custom control");
Here is where the problem comes in. At this point both the tempTabPage and the customView are the same size with no padding or margin and they are the size I want them to be. I now try to add this new custom UserControl to the tab page like this:
tempTabPage.Controls.Add(customView);
When making this call the customView and it's children controls get resized to be larger and so parts of the customView are hidden.
Can anyone give me any direction on what to look for or what could be causing this kind of issue?
Thanks ahead of time.
The UserControl's "AutoScaleMode" property should be set to "None".
If you want the customView to fill the TabPage.
Use Dock like this:
tempTabPage.Controls.Add(customView);
customView.Dock = DockStyle.Fill;
Then the customView will fill out the space in the TabPage, but you have to handle resizing of the customView so child controls will be shown properly.
I had the same issue.
The UserControl's "AutoScaleMode" set to "None" works for me.

Categories

Resources