I have a pdf browser control embedded in a wpf window. I added the reference to the acrobat library, made a custom control and placed it on a window. When i run it locally (win7) it all runs fine but when i try to run it on windows xp it doesn't. The error report says filenotfoundexception but i'm afraid it has something to do with references.
The control:
Public Class PdfControl
Public Sub New(ByVal filename As String)
InitializeComponent()
Me.AxAcroPDF1.LoadFile(filename)
End Sub
End Class
The window:
Public Class ResourceWindow
Public Sub New()
InitializeComponent()
Dim uc = New PdfControl("D:\PM_10_O_03Nov2011ENG.pdf")
Me.WindowsFormsHost1.Child = uc
End Sub
End Class
Code calling the window:
Dim resourceWindow As New ResourceWindow()
resourceWindow.Show()
Related
I've created a custom control called ecTextBox in VB.NET which uses a control template in Generic.xaml. That works.
In code behind of the custom control I override metadata in the constructor:
Public Sub New()
DefaultStyleKeyProperty.OverrideMetadata(GetType(ecTextBox), New FrameworkPropertyMetadata(GetType(ecTextBox)))
End Sub
In MainWindow.xaml I use the custom control with a simple
<ec:ecTextBox/>
That works fine.
But if I throw a second control or change the propertys of the first ecTextBox in MainWindow.xaml, I get the message "PropertyMetaData is already registered for type ecTextBox".
In StackOverflow I've read, that C# programmers should use the static-Keyword for the constructor. But if I change the constructor to
Shared Sub New
DefaultStyleKeyProperty.OverrideMetadata(GetType(ecTextBox), New FrameworkPropertyMetadata(GetType(ecTextBox)))
End Sub
the second custom control don't uses the control template but appears as a normal TextBox without Border.
What is the correct way to override the metadata for all used ecTextBox controls and prevent the errors?
This is the solution:
Public Sub New()
MyBase.New()
End Sub
Shared Sub New()
DefaultStyleKeyProperty.OverrideMetadata(GetType(ecTextBox), New FrameworkPropertyMetadata(GetType(ecTextBox)))
End Sub
In the code below I am unable to get the WPF Window to be updated from a ansynchronous call. All that is shown is the line "First item". The problem is that the Windowis not launched from a WPF Application, but from a class module. As our main UI application is a VB6 application it launches som WPF elements though calls to a Com visible Net dll. This works very well, but not in the case below.
THE MAIN CONSOLE APPLICATION
Imports Window
Imports System.Windows
Imports System.Threading
Module Module1
Sub Main()
Dim launcher As New WindowLauncher
launcher.LaunchWindow()
Console.WriteLine("Press a key to continue...")
Console.ReadLine()
End Sub
End Module
THE WPF WINDOW LAUNCHER
Imports Window
Public Class WindowLauncher
Public Sub LaunchWindow()
Dim model As New ViewModel
Dim window As New DisplayWindow
model.Dispatcher = window.Dispatcher
window.DataContext = model
window.Show()
model.Collection.Add("Second item.")
model.StartAddingItems()
'window.Close()
End Sub
End Class
THE WPF WINDOW AND ITS VIEWMODEL IN WPF USERCONTROL LIBRARY PROJECT
<Window x:Class="DisplayWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DisplayWindow" Height="300" Width="300">
<Grid>
<ListBox ItemsSource="{Binding Collection}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Imports System.Collections.ObjectModel
Imports System.Threading
Imports System.Windows.Threading
Public Class ViewModel
Public Sub New()
Collection = New ObservableCollection(Of String)
Collection.Add("First item")
End Sub
Public Property Collection As ObservableCollection(Of String)
Public Property Dispatcher As Dispatcher
Public Sub StartAddingItems()
Dim progress As New Progress(Of String)
AddHandler progress.ProgressChanged, AddressOf ProgressChanged
For i = 1 To 10
DoSomething(progress).Wait()
Next
End Sub
Private _counter As Integer
Private Async Function DoSomething(progress As IProgress(Of String)) As Task
Await Task.Delay(10 * _counter)
_counter += 1
progress.Report(CStr(_counter))
End Function
Private Sub ProgressChanged(sender As Object, e As Object)
Dim text = CStr(e)
Me.Dispatcher.BeginInvoke(Sub() AddToCollection(text), DispatcherPriority.Background)
'The challenge seems to be to find the correct Dispatcher. Now the property is set from the WPF Window, but the code never reaches the AddToCollection method. `
AddToCollection(text)
`This call throws the well known "This type of CollectionView does not support changes..." exception.`
End Sub
Private Sub AddToCollection(text As String)
Collection.Add(String.Format("item {0}", text))
End Sub
End Class
The problem lies in the following calls:
model.Collection.Add("Second item.")
model.StartAddingItems()
This seems to block updates to the user interface.
I moved these calls to the window.Loaded event of the WPF.Form (the form holds a reference to the viewmodel) and I set the viewmodel's Dispatcher to that of the window there.
If you're displaying WPF windows, you really need a separate WPF thread (with an STA main loop):
var thread = new Thread(() =>
{
var application = new Application();
application.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
Consider a class that inherits from System.Windows.Window like so:
Public Class MyWindow
Inherits Window
Private _root As Grid
Public Sub New()
MyBase.New()
_root = New Grid
Me.AddChild(_root)
End Sub
Private Sub Me_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
Dim image As New Image
Dim bitmapImage As New BitmapImage(New Uri("Assets/MyImage.png", UriKind.Relative))
image.Source = bitmapImage
image.Width = 100
image.Height = 100
image.Stretch = Stretch.Fill
_root.Children.Add(image)
End Sub
End Class
Let it be part of a WPF Windows Application that has the following module as its startup object:
Module MyModule
Sub main()
Dim myApplication As New Application
myApplication.Run(New MyWindow)
End Sub
End Module
The window gets displayed, but the image does not. When inserting the exact same image loading code in the Loaded event of a VS default MainWindow class (MainWindow.xaml.vb), the image shows up as expected. MyImage.png has 'Build Action' set to 'Resource' in both cases. What am I missing here?
Edit:
I learned that such references in codebehind must be specified using the Pack URI scheme, so replacing the Uri code with
New Uri("pack://application:,,,/Assets/MyImage.png")
will make it work. The problem was that the relative Uri was interpreted as 'file system absolute' (despite having specified UriKind.Relative), and the image location got resolved to C:\Assets\MyImage.png.
But that doesn't answer the underlying question: Why does
New Uri("Assets/MyImage.png", UriKind.Relative)
work when used in the codebehind of the standard MainWindow class (which also inherits Window, but additionally has some associated XAML), but not in a 'bareboned' descendant of Window like the MyWindow class above (defined in code only)?
Apparently, the Uri was interpreted as absolute - even though I specified it as UriKind.Relative.
When replacing with
Dim bitmapImage As New BitmapImage(New Uri("pack://application:,,,/Assets/MyImage.png"))
it works.
I have a WPF Project to which i've added a Windows Form.
The windows form has a method runme(). But I'd like to call it from the WPF form.
Currently I've used
Dim wpfForm as new wpfForm
wpfForm.Show()
to display the the WPF form from a Windows form.
I'm not sure how to send a command back though.
I've tried:
Me.parent.runme()
But this gives me errors
The only way that I can think of to do what you are wanting is to create a Custom Constructor for your Winform and pass the reference to the Wpf Window to it. There appears to be no easy way to assign a WPF Window as an Owner/Parent of a Winforms Window.
Winforms Form
Public Class Form1
Dim myParent As System.Windows.Window
Public Sub New()
InitializeComponent()
End Sub
Public Sub New(parent As System.Windows.Window)
myParent = parent
InitializeComponent()
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
CType(myParent, MainWindow).runMe()
End Sub
End Class
Wpf Form
Class MainWindow
Dim winForm As Form1
Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Button1.Click
winForm = New Form1(Me)
winForm.Show()
End Sub
Public Sub runMe()
Me.Background = Brushes.Red
End Sub
End Class
Eventually what worked was to create an interface as suggested by Cyborgx37
Interface ILogOut
Sub DoIt()
End Interface
Class WinFormWindow : Implements ILogOut
Public Sub DoIt() Implements ILogOut.DoIt
MsgBox("Message Received!")
End Sub
End Class
You can then use the ILogOut interface to send a message to the Windows forms window from a WPF window
Can anyone suggest approaches that will allow me to change the properties of a host WinForm from a WPF element in an ElementHost?
I have an MVVM application using Prism that's bound to an ElementHost. I would like to change the WinForm title, resize the WinForm and close the WinForm from within my ViewModel.
I understand receiving data from a WPF composite control described in this article but I can't see how that will work in a ViewModel.
App is the WinForm
ChartWizardViewModel is the ViewModel I want to change the properties of App from.
Everything else is the Prism architecture. Shell, Bootstrapper etc.
Public Class App
Public Sub New(ByVal modulesToLoad As List(Of String))
' This call is required by the designer.
InitializeComponent()
If Application.Current Is Nothing Then
Dim wpfAppAdapter As New WpfApplicationAdapter
End If
' Load the application modules
Dim formBootstrapper As New Bootstrapper(modulesToLoad)
formBootstrapper.Run()
' Get the current instance of shell and bind it to the ElementHost
Dim shellElement = formBootstrapper.Container.Resolve(Of Shell)()
ehMaster.Child = shellElement
End Sub
End Class
Public NotInheritable Class Bootstrapper
Inherits UnityBootstrapper
Private _modulesToLoad As List(Of String) ' The modules that we want to load
Public Sub New(ByVal modulesToLoad As List(Of String))
_modulesToLoad = modulesToLoad
End Sub
Protected Overrides Function CreateShell() As DependencyObject
Dim shell = Container.Resolve(Of Shell)()
Return shell
End Function
Protected Overrides Function GetModuleCatalog() As IModuleCatalog
Dim catalog As ModuleCatalog = New ConfigurationModuleCatalog()
For Each moduleToLoad As String In _modulesToLoad
Select Case StringHelper.CleanString(moduleToLoad)
Case "chartwizardmodule"
catalog.AddModule(GetType(ChartWizardModule))
End Select
Next
Return catalog
End Function
End Class
Public NotInheritable Class ChartWizardModule
Implements IModule
Private ReadOnly regionManager As IRegionManager
Public Sub Initialize() Implements IModule.Initialize
regionManager.RegisterViewWithRegion("MainRegion", GetType(MainWindow))
End Sub
Public Sub New(regionManager As IRegionManager)
Me.regionManager = regionManager
End Sub
End Class
Partial Public Class MainWindow
Private _objChartWizardViewModel As ChartWizardViewModel ' The chart wizard base view model that controls the rest of the views
Private Sub MainWindow_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
Dim objChartWizardViewModel As New ChartWizardViewModel()
_objChartWizardViewModel = objChartWizardViewModel
' Data Context for the Chart Wizard
Me.DataContext = _objChartWizardViewModel
End Sub
End Class
Public Class ChartWizardViewModel
Implements INotifyPropertyChanged
' I need to change the properties of the WinForm (App) from here
End Class
I solved this with an EventAggregator as discussed in this post
Using EventAggregator to communicate between WPF in ElementHost and host WinForm