In my wpf application i try to show a webView2 for a login, even though when i navigate to the view and start the initialization nothing happens. I've tried many options and solutions i found in the internet and that worked for others but nothing helped.
The Code:
private WebView2 m_webView21;
public WebView2 WebView21 { get => m_webView21; set => SetProperty(ref m_webView21, value); }
protected async Task<WebView2> CreateBrowserAndLoadUrlAsync(string url)
{
webView21 = new WebView2();
webView21.CoreWebView2InitializationCompleted += WebView21_CoreWebView2InitializationCompleted;
Debug.WriteLine("InitializeAsync");
await webView21.EnsureCoreWebView2Async();
Debug.WriteLine("WebView2 Runtime version: " + webView21.CoreWebView2.Environment.BrowserVersionString);
SetBrowserHostVisibility(Visibility.Visible);
if (webView21 != null && webView21.CoreWebView2 != null)
{
webView21.CoreWebView2.Navigate(url);
}
return webView21;
}
private void WebView21_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e)
{
webView21.Loaded += Browser_FrameLoadEnd;
webView21.Initialized += Browser_InitializedChanged;
}
--Xaml Code--
<Grid Background="Transparent">
<wv2:WebView2 Visibility="Visible" Source="{Binding WebView21.Source.AbsoluteUri, Mode=OneWay}"/>
</Grid>
This is the first thing i'm calling in my viewmodel from the OnNavigatedTo(). Everything works as it should untig it comes to the EnsureCoreWebViewAsync() - from this function it never returns - just nothing happens.
When i do not initialize the webview2 and just set the source to the uri everything works fine aswell. But no events or anything get fired (e.g. NavigationCompleted, SourceChanged, etc.) and i need those events ofc.
I installed the correct runtime i also installed the WebView2 Plugin of course. Also tried different enviroments nothing helped.
So the actual question is, is it even possible to initialize the WebView2 from the Viewmodel?
I found the solution. I had to use a placeholder in my xaml which later init's the webView2 in my Viewmodel.
Just change the xaml code from the question with this and it should work fine
<ContentControl Content="{Binding WebView21, Mode=OneWay}" />
Thanks for all the helpful comments :))
Related
I have a UWP app, with two Pages: MainPage and EventPage. On both of these there is a splitView, and at the top of this a GridView with two buttons - one to navigate to MainPage, and one to navigate to EventPage. The XAML for the buttons looks like this:
<Button Content="Browse by system"
HorizontalAlignment="Center"
Margin="0,0,0,0"
VerticalAlignment="Top"
Width="250"
Click="SystemButtonClick"/>
However, when i press the "Browse by system" button, the app crashes. Here is the constructor for the page:
public EventPage()
{
this.InitializeComponent();
var systemList = SystemClass.GetSystems();
systemList.Sort();
Systems = new ObservableCollection<string> (systemList);
}
It passes the constructor fine, and instead crashes when exiting the eventhandler for the button click:
private void SystemButtonClick(object sender, RoutedEventArgs e)
{
this.Frame.Navigate(typeof(EventPage));
}
I've modeled this after the Peer-to-peer navigation tutorial from microsoft, and can't find any significant differences. The only similar issue I could find here was this, but that seemed to be due to the Template10 package which I'm not using.
When the crash does occur, it goes to the App.g.i.cs file and complains that the debugger isn't configured to debug this unhandled exception.
Does anyone have any idea why this might be happening?
EDIT: To add, if I click the button to move to the current page, it reloads fine. I also just tried starting the program to the EventPage, which also prompted a crash.
EDIT2: After some further testing, it seems I've located the source of the crash, though I don't understand it.
At the beginning of my EventPage class, I have a few variables:
public sealed partial class EventPage : Page
{
private ObservableCollection<EventBin> EventCollection;
private ObservableCollection<String> Systems;
public EventPage()
{
this.InitializeComponent();
Systems = SystemClass.GetSystems();
}
It seems that the crass occurs when I assign the Systems variable. This doesn't occur with my identical operation for the other page, with a different variable. The only difference being that in the MainPage, it's an ObservableCollection of a custom class rather than of strings.
If I re-initialize the System variable like this:
var Systems = SystemClass.GetSystems();
It runs, but doesn't connect to my bindings in the XAML.
So, it turned out that the issue was that I had bound a custom type to the list in my data template, and then tried feeding it plain strings.
<DataTemplate x:Key="System_DefaultItemTemplate"
x:DataType="local:SystemClass">
<StackPanel>
<TextBlock Text="{x:Bind Name}"/>
<TextBlock Text="{x:Bind Site}"/>
</StackPanel>
</DataTemplate>
Since the strings obviously didn't have any Name or Site properties, it crashed.
I've read other cases posted here un StackOverflow about this message but I'm not clear how to apply the changes to my problem. I have a small application made with WPF and my ignorance of xaml is taking its toll. I compile and everything is fine but when running in debug mode, in the output window in VS2015 I see
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=lbEnfermedades'. BindingExpression:(no path); DataItem=null; target element is 'MenuItem' (Name=''); target property is 'CommandTarget' (type 'IInputElement')
I see that I'm not the only one having problems with context menus. I created a class using RoutedUICommand as suggested:
namespace Maqueta
{
class CommandLibrary
{
private static RoutedUICommand relacionados = new RoutedUICommand("Relacionados", "BuscarRelacionados", typeof(CommandLibrary));
public static RoutedUICommand BuscarRelacionados
{
get { return relacionados; }
}
}
}
I have this portion of Xaml, maybe the nesting of controls I'm doing is forbidden? In a tabcontrol I put a listbox and then attached a context menu:
<TabControl x:Name="tabControl" Grid.Column="1" HorizontalAlignment="Left" Height="287" Margin="10,243,0,0" VerticalAlignment="Top" Width="709" TabStripPlacement="Top" Grid.ColumnSpan="3">
<TabItem Header="Enfermedades">
<ListBox x:Name="lbEnfermedades" Grid.Column="1" Grid.ColumnSpan="3">
<ListBox.ContextMenu>
<ContextMenu IsEnabled="True" IsManipulationEnabled="True">
<MenuItem Command="local:CommandLibrary.BuscarRelacionados"
CommandTarget="{Binding ElementName=lbEnfermedades}"
Header="BuscarRelacionados" IsEnabled="True"/>
</ContextMenu>
</ListBox.ContextMenu>
<ListBox.CommandBindings>
<CommandBinding Command="local:CommandLibrary.BuscarRelacionados" CanExecute="CanBuscarRelacionadosExecute" Executed="OnBuscarRelacionadosExecute" />
</ListBox.CommandBindings>
<CheckBox/>
</ListBox>
</TabItem>
<TabItem Header="Medicamentos">
<ListBox x:Name="lbMedicamentos" Grid.Column="1" Grid.ColumnSpan="3"/>
</TabItem>
<TabItem Header="Procedimientos">
<ListBox x:Name="lbProcedimientos" Grid.Column="1" Grid.ColumnSpan="3"/>
</TabItem>
</TabControl>
I also created the routines that should be called, using another post here as an example:
private void OnBuscarRelacionadosExecute(object sender, ExecutedRoutedEventArgs e)
{
ListBox lb = sender as ListBox;
if (lb != null)
{
if (lb.SelectedItem != null)
{
//lb.Items.Remove(lv.SelectedItem);
MessageBox.Show(lb.SelectedItem.ToString());
e.Handled = true;
}
}
}
private void CanBuscarRelacionadosExecute(object sender, CanExecuteRoutedEventArgs e)
{
ListBox lb = sender as ListBox;
if (lb != null)
{
e.CanExecute = true;//lb.SelectedItem != null;
e.Handled = true;
}
}
These methods are never called and the context menu appears grayed (disabled) when I right click on the listbox. I understand this is because the "cannot find source for binding" message. Any pointers to a throrough explanation of xaml binding would be appreciated because the tips I see in other posts (for example, "use relative binding") are a mystery for me. Couldn't find the definive doc at Microsoft site either. I wish using context menues were a more intuitive task. Thanks.
Claudio.
The CommandTarget attribute of your context menu is superfluous. The error message you are seeing simply means that the command target is ignored. So take out command target. The command binding that you have defined for the list box will be the command target.
Despite that, your context menu works for me with or without the CommandTarget attribute...so something else is wrong in a part of your code you haven't shared with us.
Your XAML, routed command implementation and command binding all look fine. So it seems to me that you are looking in the wrong place for the problem...a common symptom that arises when your binding are not working.
Unfortunately cannot refer you to a "thorough explanation of [WPF] binding" because all the stuff you need to master is scattered among diverse sources. The only explanations of binding that exist in one place are see-spot-run...and you are well beyond that.
In my experience the only way to explore the intricacies of binding is maintain a set of test code you can experiment on. Good luck.
Thanks to the person that took the time to answer. I continued looking for ideas in this site but nothing seemed to help. Finally, today I added a little part:
<MenuItem Command="local:CommandLibrary.BuscarRelacionados"
CommandTarget="{Binding ElementName=local:lbEnfermedades}"
Header="BuscarRelacionados" IsEnabled="True"/>
I changed ElementName=lbEnfermedades to
ElementName=local:lbEnfermedades. I don't know why it's necessary, it was just a wild hunch. Now the event handlers I defined are working as expected and my menu item is not disabled anymore when the context menu appears. Hope someone else may find it useful.
I'm trying to use both AvalonDock 2.0 (MVVM-compliant) and Caliburn Micro in my WPF application. All works fine, except for a couple of issues connected with closing document panes or hiding tool panes.
My main viewmodel derives from Conductor<IScreen>.Collection.OneActive and exposes two BindableCollection's of Screen-derived viewmodels for Tools and Documents; the corresponding relevant XAML is like:
<xcad:DockingManager Grid.Row="1"
AnchorablesSource="{Binding Path=Tools}"
DocumentsSource="{Binding Path=Documents}"
ActiveContent="{Binding Path=ActiveItem, Mode=TwoWay}">
<xcad:DockingManager.LayoutItemContainerStyle>
<Style TargetType="{x:Type xcad:LayoutItem}">
<Setter Property="Title" Value="{Binding Model.DisplayName}" />
</Style>
</xcad:DockingManager.LayoutItemContainerStyle>
<xcad:DockingManager.LayoutItemTemplateSelector>
<views:AutobinderTemplateSelector>
<views:AutobinderTemplateSelector.Template>
<DataTemplate>
<ContentControl cal:View.Model="{Binding . }" IsTabStop="False" />
</DataTemplate>
</views:AutobinderTemplateSelector.Template>
</views:AutobinderTemplateSelector>
</xcad:DockingManager.LayoutItemTemplateSelector>
<xcad:LayoutRoot>
<xcad:LayoutPanel Orientation="Horizontal">
<xcad:LayoutAnchorablePane DockHeight="150" DockMinWidth="200">
</xcad:LayoutAnchorablePane>
<xcad:LayoutDocumentPane/>
</xcad:LayoutPanel>
</xcad:LayoutRoot>
</xcad:DockingManager>
The template selector is as simple as that:
public class AutobinderTemplateSelector : DataTemplateSelector
{
public DataTemplate Template { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
return Template;
}
}
1. Closing Documents
The first issue comes when handling document-pane close. AD has its document handling mechanism, which should be synchronized with CM's one. CM is based on a screen conductor; when a screen needs to be closed, the method TryClose is used to close it if possible (i.e. unless a guard method tells the framework that the screen cannot be closed, e.g. because the document is dirty). To let AD play with CM I'm using a workaround similar to that described in Prevent document from closing in DockingManager, where the main view code directly calls this method handling the docking manager closing event: when AD is closing the document, call the underlying VM guard method and cancel if required; if not cancelled, then AD goes on closing thus firing the DocumentClosed event.
To see if this could work, I first created a public TryClose method in the document viewmodel base, essentially duplicating the code in the CM TryClose override, like (IsDirty is a protected virtual method overridden by descendant viewmodels):
public bool CanClose()
{
if (!IsDirty()) return true;
MessageBoxAction prompt = new MessageBoxAction
{ ...prompt message here... };
bool bResult = true;
prompt.Completed += (sender, args) =>
{
bResult = prompt.Result == MessageBoxResult.Yes;
};
prompt.Execute(null);
return bResult;
}
This is the method called by the main view code behind in the handlers for AD document closing and document closed:
private void OnDocumentClosing(object sender, DocumentClosingEventArgs e)
{
DocumentBase doc = e.Document.Content as DocumentBase;
if (doc == null) return;
e.Cancel = !doc.CanClose();
}
private void OnDocumentClosed(object sender, DocumentClosedEventArgs e)
{
DocumentBase editor = e.Document.Content as DocumentBase;
if (doc != null) doc.TryClose();
}
Note that I cannot directly call TryClose in OnDocumentClosing, as this would cause null object reference errors in AD. This is really ugly but it works. I can now close documents and my guard methods are called appropriately before proceeding. Anyway, it would be nice to get suggestions for a less hacky solution here.
2. Hiding Tools
Another issue arises from hiding the tools panes. In this case, AD should just hide them. The AD control visibility can be bound to an IsVisible boolean property in my viewmodels implementing tool panes, using a BooleanToVisibility converter. To this end I just add the binding in the XAML:
<xcad:DockingManager.LayoutItemContainerStyle>
<Style TargetType="{x:Type xcad:LayoutItem}">
...
<Setter Property="Visibility"
Value="{Binding Model.IsVisible, Mode=TwoWay, Converter={StaticResource BooleanToVisibilityCvt}}"/>
...
Now, if I hide a tool pane by clicking on its X button, I can see that my VM IsVisible property is set to false as expected, and the pane is hidden. Then, if I programmatically set this property back to true the pane is not shown. Even restoring the layout does not work: I can see that when the application starts and the object corresponding to the hidden VM is being added to the Tools collection its IsVisible is already false. To have it back, I must set this to true and then restore the layout. If I miss any of the two steps, the pane remains hidden. Clearly I'm not following the intended implementation strategy here. Could anyone point me in the right direction?
I am developing a desktop application using Modern UI for WPF. I try to refresh my tab page when I go to a new tab page, but I couldn't.
I want to refresh my MUI WPF tab page when I go to another page using my tab controller.
Can anyone help me?
I'm not quite sure what you mean exactly, but by calling InvalidateVisual() on a control, you can force a visual refresh of it if that's what you're after, as it sounds like you've got a WPF control that isn't being updated when the data is changing.
Based on the MSDN documentation, this:
Invalidates the rendering of the element, and forces a complete new layout pass. OnRender is called after the layout cycle is completed.
For example:
var grid = new Grid();
// Our grid should refresh after this,
// although in normal circumstances it would by default regardless.
grid.InvalidateVisual();
I hope that this is of use.
You can use SelectionChanged event to handle this. You can refresh MUI WPF tab page by using SelectionChanged.
<TabControl x:Name="MyTab" SelectionChanged="MyTabControl_SelectionChanged">
<TabItem x:Name="TabItem1" Header="Tab 1"/>
<TabItem x:Name="TabItem2" Header="Tab 2"/>
<TabItem x:Name="TabItem3" Header="Tab 3"/>
</TabControl>
Then you can access to each TabItem at the event:
private void MyTabControl_SelectionChanged(object sender, SelectionChangedEventArgs e){
if (TabItem1.IsSelected){}
if (TabItem2.IsSelected){}
if (TabItem3.IsSelected){}
}
While the selected answer is ok, it might not be the best way to go about it.
MUI includes a content navigation framework that handles content loading, unloading and history navigation based on link uris. If you want your content to be aware of navigation events such as loaded and unloaded events, you'll need to implement an interface.
Make your content navigation aware by implementing the IContent interface available in the FirstFloor.ModernUI.Windows namespace.
A simple Example is :
public class MyContent : UserControl, IContent
{
public void OnFragmentNavigation(FragmentNavigationEventArgs e)
{
}
public void OnNavigatedFrom(NavigationEventArgs e)
{
}
public void OnNavigatedTo(NavigationEventArgs e)
{
//Refresh your page here
}
public void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
// ask user if navigating away is ok
if (ModernDialog.ShowMessage("Navigate away?", "navigate", MessageBoxButton.YesNo) == MessageBoxResult.No) {
e.Cancel = true;
}
}
}
I am experiencing a very weird problem: In WPF I have a tabControl which contains 3 tabItems. I have made a binding from the tabControl's SelectedIndex to a property inside my viewModel class in "OneWayToSource" mode.
Here's the XAML code:
<TabControl Name="mainTabControl" SelectedIndex="{Binding SelectedTabIndex, Mode=OneWayToSource}" >
<TabItem Header="Tab 01" Name="tab01"> ... </TabItem>
<TabItem Header="Tab 02" Name="tab02"> ... </TabItem>
<TabItem Header="Tab 03" Name="tab03"> ... </TabItem>
</TabControl>
And in my viewModel:
private int m_selectedTabIndex;
public int SelectedTabIndex
{
get
{ return m_selectedTabIndex; }
set
{
SetAndNotify(ref m_selectedTabIndex, value, () => SelectedTabIndex);
SelectedTabChanged();
}
}
private void SelectedTabChanged()
{
// Some code
}
As you can see, everytime my viewModel's SelectedTabIndex property changes, the SelectedTabChanged() method is executed, this works perfectly.
My weird problem is that: When I show a message using for example System.Windows.MessageBox.Show("Some Text") inside my SelectedTabChanged() method, I select another tabItem and the previous selected tab gets blocked, it looks like selected, but it remains selected permanently, I cannot see its content anymore.
Just to clarify: As I stated before, this weird issue only happens when a modal window is showed
Why is happening? How can I solve this issue?
I hope I explained myself clearly.
Thank you in advance.
I have solved my problem. Since I am new in WPF I really dont understand why a modal window make the tabs get blocked. But I was searching and found that the Dispatcher class allows one to execute asynchronously a method which prevent any control from get blocked.
I changed my viewModel code as below:
public int SelectedTabIndex
{
get
{ return m_selectedTabIndex; }
set
{
SetAndNotify(ref m_selectedTabIndex, value, () => SelectedTabIndex);
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(SelectedTabChanged), null);
}
}
The line that really helped me was the following:
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(SelectedTabChanged), null);
Hope this help someone else can be experiencing some similar problem.
Im not 100% sure I understand your problem, but a MessageBox.Show will spawn a nested message pump and block the main Dispatcher, thus 'freezing' the main window (which is why it is modal).
If you need to show a MessageBox style alert without it being modal, then my advice is to create a panel with your message in it that exists in the TabItem with a hidden visibility, then make it visible when required to show you message. Your Tab selections should still work in that scenario