WPF - programmatically referencing image resource in codebehind of Window with no XAML - wpf

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.

Related

WPF Dependency Property - set from XAML

I am trying to achieve the following in a WPF personal finance app:
In various places I want to display a user control giving details of a asset holding (usually a share, bond etc), the target asset may be changed dynamically by the user in which case the control must be refreshed. Each Asset has a unique identifier, AssetId.
I am using MVVM and I've developed a single window with a View Model that takes AssetID as a parameter (property) and retrieves the relevant details for binding to the View. This work fine. What I'd like to do is make a generic user control with the same functionality so I can basically drop that 'window' inside other windows.
So I pretty much copy-pasted the XAML from that form into a User Control, where I'm struggling is passing in the AssetId from the parent window to the child control.
Google tells me I need a dependency property and here's where I am
Public Class HoldingView
Private _AssetId As Integer
Public AssetIdProperty As DependencyProperty = DependencyProperty.Register("AssetId",
GetType(Integer),
GetType(HoldingView),
New FrameworkPropertyMetadata(New PropertyChangedCallback(AddressOf AssetIDChanged)))
Public Property AssetId As Integer
Get
Return GetValue(AssetIdProperty)
End Get
Set(value As Integer)
SetValue(AssetIdProperty, value)
End Set
End Property
Private Sub AssetIDChanged(d As DependencyObject, e As DependencyPropertyChangedEventArgs)
Dim NewAssetId As Integer
NewAssetId = e.NewValue
Me.DataContext.AssetId = NewAssetId
End Sub
Public Sub New()
' This call is required by the designer.
InitializeComponent()
Me.DataContext = New HoldingViewmodel
End Sub
End Class
Called like this:
<Grid>
<local:HoldingView AssetId="{Binding AssetId}"/>
</Grid>
The code compiles and runs but when I try and load the window that has the user control, the app crashes with this message:
A 'Binding' cannot be set on the 'AssetId' property of type 'HoldingView'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
Which is not that helpful. From my Googling, you can also get this message if the syntax of the DP registration is not spot on, but it looks Ok to my inexperienced eye...
Anybody else had this?
Public AssetIdProperty As DependencyProperty
should be
Public Shared ReadOnly AssetIdProperty As DependencyProperty
Please take a look at Custom Dependency Properties.
Also remove
Me.DataContext = New HoldingViewmodel
because that will effectively break any DataContext-based Bindings like
AssetId="{Binding AssetId}"
where the source property is supposed to be owned by the object in the inherited DataContext, which usually is an object in the application's view model.
Controls should never have their own, "private" view model, but instead handle property changes in code behind. In case of UserControls, there could simply be UI elements in their XAML that would be bound to the UserConrol's own properties.
Hence
Me.DataContext.AssetId = NewAssetId
in the PropertyChangedCallback is pointless and should be removed, as well as
Private _AssetId As Integer
To summarize, it should look like this:
Public Class HoldingView
Public Shared ReadOnly AssetIdProperty As DependencyProperty =
DependencyProperty.Register(
"AssetId",
GetType(Integer),
GetType(HoldingView),
New FrameworkPropertyMetadata(
New PropertyChangedCallback(AddressOf AssetIdPropertyChanged)))
Public Property AssetId As Integer
Get
Return GetValue(AssetIdProperty)
End Get
Set(value As Integer)
SetValue(AssetIdProperty, value)
End Set
End Property
Private Shared Sub AssetIdPropertyChanged(
d As DependencyObject, e As DependencyPropertyChangedEventArgs)
CType(d, HoldingView).AssetIdChanged(e.NewValue)
End Sub
Private Sub AssetIdChanged(id As Integer)
...
End Sub
Public Sub New()
InitializeComponent()
End Sub
End Class

Showing saved Xaml Canvas through binding

I'm saving an svg image as xaml string in a database. Next I record this xaml string in a property of a class (MyClass.XamlString) .
On my form I have a Canvas, and I want MyClass.XamlString to be the child of the canvas.
This is what I have:
Dim MyBinding As New Binding("XamlString")
MyBinding.Source = MyClass
MyBinding.Converter = New clsXamlToCanvasConverter
CanvasOnForm.SetBinding(ContentPresenter.ContentProperty, MyBinding)
and
Friend Class clsXamlToCanvasConverter
Implements IValueConverter
Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IValueConverter.Convert
Dim ConvertedCanvas As Canvas = System.Windows.Markup.XamlReader.Parse("<Canvas xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">" & value & "</Canvas>")
Return ConvertedCanvas
End Function
Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack
Throw New NotImplementedException
End Function
End Class
In debugging I see the clsXamlToCanvasConverter creates a canvas with children from the xaml string, this is working correctly although you might say the extra canvas is redundant.
My guess is this is where I'm going wrong: CanvasOnForm.SetBinding(ContentPresenter.ContentProperty, MyBinding)
The code runs fine, the problem is I don't see the image displayed.
I've been searching a lot on this and I've seen this post WPF What is the correct way of using SVG files as icons in WPF , but apparently this hasn't helped me out.
Any ideas?

How to access control of another class in mainwindow WPF using vb

I'm trying to call text box in another class from the MainWindow in WPf using this code:
Private Sub Button_Click_1(sender As Object, e As RoutedEventArgs)
Mainwindowtext2.Text = DirectCast(Application.Current.MainWindow, Window1).text1.Text
End Sub
When I compile there are no errors, but after a Button Click this error comes out
InvalidCastException was unhandled
"Unable to cast object of type 'WpfApplication1.MainWindow' to type 'WpfApplication1.Window1'."
Is there another way to get the control from another class while in MainWindow?
The answer is in the error code you're getting:
Unable to cast object of type 'WpfApplication1.MainWindow' to type 'WpfApplication1.Window1'.
The object you have is of type 'WpfApplication1.MainWindow'. This means that you can't cast it to 'WpfApplication1.Window1'.
Because your root namespace is 'WpfApplication1', the code should read:
Private Sub Button_Click_1(sender As Object, e As RoutedEventArgs)
Mainwindowtext2.Text = DirectCast(Application.Current.MainWindow, MainWindow).text1.Text
End Sub
To understand why, the static property Application.Current is holding a reference to the class Application. It's MainWindow property is of type Window. In your application, your main window is type MainWindow, which derives from Window, and can therefore be returned from the Application.Current.MainWindow property. That is why you need to cast it to MainWindow.
EDIT
If you are trying to get an instance of a different window than the main window, you can use the application's Windows property:
Mainwindowtext2.Text = Application.Current.Windows.OfType(Of Window1)().First().text1.Text
The way WPF creates the backing fields, this should work as long as the classes are in the same assembly. If they aren't, consider creating a read-only property to expose the text, or set the FieldModifier property in XAML.
Please change your code:
Mainwindowtext2.Text = DirectCast(Application.Current.Window1, Window1).text1.Text
Hope This helps you...
try this...
You can use the Binding concept as below:
in .CS File:
Private _TextBoxName As String
Public Property TextBoxName() As String
Get
Return _TextBoxName
End Get
Private Set(ByVal value As String)
_TextBoxName = value
End Set
End Property
in Xaml:
< TextBox Text="{Binding TextBoxName}"/>
Now you can use the value of Textbox as Follows:
Window1textbox.Text = mainwindow.TextBoxName

I can't use Window.Show despite of creating new Window instance

here's the problem:
In my WPF application I used to load/parse my .xaml files using XamlReader.Load Method to open a window in my application.
Codefragment of my function which return the window:
Dim win As New Window()
Dim myObject As Object
Dim xml As XmlReader = XmlReader.Create("mysample.xaml")
myObject = System.Windows.Markup.XamlReader.Load(xml)
win = CType(myObject, Window)
Return win
I use this to display all my different windows the user wants to see.
I open the window with win.Show and close it, when user switch to another window with win.Close. It works well!
Now to increase the performance I plan to do all the XAMLReader.Load at Application Start and store the information into a Dictionary:
Private Shared windict As Dictionary(Of String, Object)
Public Shared Sub ConvertXAMLToWindow(ByVal formName As String)
windict = New Dictionary(Of String, Object)
Dim myObject As Object
Dim xml As XmlReader = XmlReader.Create(formName)
myObject = System.Windows.Markup.XamlReader.Load(xml)
windict.Add(formName, myObject)
End Sub
Then I want to use that information when calling windows:
If windict.ContainsKey(formName) Then
Dim win As New Window()
Dim myObject As Object
myObject = windict(formName)
win = CType(myObject, Window)
Return win
End If
Now
This works well, but when I use win.Close to close my window I get an error when trying to open it again with win.Show, although I create an new instance of Window?
System.InvalidOperationException
Cannot set Visibility or call Show, ShowDialog... after a Window has
closed.
But it works when I don't use the Dictionary Method but the XAMLReader.Load directly - any ideas whats going on ? Somehow the window I get by returning XamlReader.Load seems different than the stored information from the dict?? Am I missing somehting? Thanks in advance!
You could use Hide() instead of Close()
Hide hides the Form, so instead of disposing of the form (and its controls) you make it invisible. Show will make it visible again.
Be careful though, the form in the dictionary will still hold the state from the previous time it was used.

filenotfoundexpection when opening pdf in wpf windows

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()

Resources