Showing saved Xaml Canvas through binding - wpf

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?

Related

Correctly bind object instance property to a Label in code

This is supposed to be easy, yet I can't get it to work.
This is a simplified example so I can illustrate my problem. I have a List(Of Object) and I want to bind the Content of a Label to some property of an object in the list. I want to do this in code (Because those labels will be generated in runtime).
I create my object that will hold the value for the label and the list, that will hold those objects:
' The List to hold objects
Public Class BList
Public Shared listy As New List(Of BindTest)
End Class
' Object to hold label text
Public Class BindTest
Public Property Namy As String
End Class
Then I try to create the object and add it to the list. And try to set the binding for the label (for sake of simplicity, lets say I want bind to the first list item).
Dim bb As New BindTest
bb.Namy = "FirstName"
BList.listy.Add(bb)
B_label.SetBinding(Label.ContentProperty, "Namy")
B_label.DataContext = BList.listy.Item(0)
So far it works fine and label shows "FirstName" as expected. But then if I try to change the value of that first item like this:
BList.listy.Item(0).Namy = "Something else"
nothing happens and the label is not updated.
Thanks to Mike Eason.
I needed to implement INotifyPropertyChanged. I somehow thought, that it would be implemented automatically with all that WPF default-way of databinding everything. Oh well, one needs implement this manually.
So for the code to work, this part:
' Object to hold label text
Public Class BindTest
Public Property Namy As String
End Class
..must be changed to this:
' Object to hold label text
Public Class BindTest
Implements INotifyPropertyChanged
Private _Namy As String
Public Property Namy
Set(value)
_Namy = value
_PropertyChanged("Namy")
End Set
Get
Return _Namy
End Get
End Property
Private Sub _PropertyChanged(Optional ByVal PropertyName As String = Nothing)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(PropertyName))
End Sub
Private Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
End Class

Load WPF UserControl dynamically

I have an abstract base class aComponent and sub-classes CriteriaList, Question, etc.
For each sub-class I have two corresponding UserControls which have names like ueCriteriaList, ubCriteriaList, ueQuestion, ubQuestion, etc. (ue stands short for "UserControl with input elements", and ub for "UserControl with buttons".)
The DataContext is the "ControllerClass" with a property with my_aComponent as the getter for the actual aComponent instance. When the aComponent instance changes (for example to an instance of CriteriaList), I want to load the corresponding UserControls (in this case ueCriteriaList and ubCriteriaList).
I have two converters ueControlConverter and ubControlConverter which take the class name (e.g. CriteriaList) and return a UserControl instance (in this case, ueCriteriaList).
Public Class ueControlConverter
Implements IValueConverter
Public Function Convert(value As Object, targetType As Type, parameter As Object,
culture As System.Globalization.CultureInfo) As Object
Implements IValueConverter.Convert
Dim aComp As aComponent = value
Dim assemblyKlassenname As String = aComp.GetType.ToString
Dim assemblyName As String = Left(assemblyKlassenname,
assemblyKlassenname.IndexOf(".") + 1)
Dim klassenName As String = Right(assemblyKlassenname,
assemblyKlassenname.IndexOf(".") - 1)
Dim t As Type = Type.GetType(assemblyName & "ue" & klassenName)
Dim o As UserControl = Activator.CreateInstance(t)
o.DataContext = value
Return o
End Function
Public Function ConvertBack(value As Object, targetType As Type, parameter As Object,
culture As System.Globalization.CultureInfo) As Object
Implements IValueConverter.ConvertBack
Return value
End Function
End Class
In XAML I have two ContentControls which bind Content="{Binding Path=my_aComponent, Converter={StaticResource _ueControlConverter} and Content="{Binding Path=my_aComponent, Converter={StaticResource _ubControlConverter}. The right UserControls are shown but without binding to my_aComponent.
What can I do?
You need to also provide the DataContext property through binding for your ContentControl objects.

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

Binding from multiple sources

My scenario:
I've got a Silverlight Application with a View, where i want to bind the textboxes to an object (two-way) and all labels to a dictionary holding the label translations.
My approach was to set the datacontext of the page to a dictionary with two items, one of them is the object and the other is the translation-dictionary.
In xaml the code looks like the following:
<TextBlock Text="{Binding [dict].[name],FallbackValue='Fallback'}" />
<TextBox Text="{Binding [obj].name,Mode=TwoWay}" />
This works initially, if I however change the object on the datacontext, the xaml is not notified about any changes and doesn't update.
I've had a working solution using a Converter for the translations, however due to the limitations on one converterparameter I didn't like the solution. In addition it wasn't possible to place a fallback-value in the textblock, which resulted in "invisible" textblocks while designing the page.
Any suggestions on how to solve this issue? It doesn't have to be using my dictionary, it would be also okay if i could set the datacontext to the object (which works) and bind the labels somehow different.
I know this will get a lot of traditional answers, but I would also like to put forward something completely original we tried (and succeeded) doing ourselves for more efficient localisation of Silverlight using Attached Properties instead of binding:
Localisation of Silverlight projects after completion
What would be the most flexible is rather than setting the DataContext for the view to a dictionary, you would be better off having the DataContext be something like a ViewModel. That is, a simple class that holds multiple properties: one for your "object" and one for your translation dictionary.
Then have the class that acts as your ViewModel implement INotifyPropertyChanged.
Create a method in your class called OnPropertyChanged that takes in a string representing your property name. In that method raise the PropertyChanged event passing in the instance of the ViewModel class and a new PropertyChangedEventArgs passing in the property name.
Back in the properties you created (object and dictionary) in the Set, after setting the value, call OnPropertyChanged passing in the string name of that property. This will notify the UI that the value of this property has changed and will essentially rebind the control to that property.
Finally, bind the Text properties of your controls on your View to the new properties you just created in your ViewModel. That should ensure that the controls on the view stay up to date.
I found a solution, but wasn't able to answer my own question (8h limit..)
I think this is just the approach Hydroslide suggested.
Create a class which holds all data and implements INotifyPropertyChanged
Public Class MyDatacontext
Implements ComponentModel.INotifyPropertyChanged
'Properties
Private _obj As Object
Private _dict As Dictionary(Of String, String)
'Events
Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
'Methods
Public Property Obj As Object
Get
Return _obj
End Get
Set(ByVal value As Object)
_obj = value
'Notify the xaml about the changed Object
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Obj"))
End Set
End Property
Public Property Dict As Dictionary(Of String, String)
Get
Return _dict
End Get
Set(ByVal value As Dictionary(Of String, String))
_dict = value
'Notify the xaml about the changed translation
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Dict"))
End Set
End Property
End Class
Define a private var in your page code
Private mycontext As New MyDatacontext
In the constructor of your page, fill your "mycontext" with the desired data
mycontext.Dict = LoadDictionary()
mycontext.Obj = LoadObject()
Me.DataContext = mycontext
Change your xaml to the following
<TextBlock Text="{Binding Dict.[name],FallbackValue=MyFallback}" />
<TextBox Text="{Binding Obj.name,Mode=TwoWay}" />
Update your object/dictionary as you like using
mycontext.Obj = LoadNextObject()

WPF ColorAnimation for a Brush property

I wonder if someone can help me - I've got a label which I need to be able to cross-fade between any 2 colors when a method is called in the code behind.
My best attempt so far:
Private OldColor as Color = Colors.White
Sub SetPulseColor(ByVal NewColor As Color)
Dim F As New Animation.ColorAnimation(OldColor, NewColor, New Duration(TimeSpan.Parse("00:00:01")))
OldColor = NewColor
F.AutoReverse = False
PulseLogo.BeginAnimation(Label.ForegroundProperty, F)
End Sub
The problem I have is that ColorAnimation returns a Media.Color and The property type for Foreground is Brush.
I know how to create the appropriate brush but not how to do it in an animation.
From Googling, it seems I need a converter:
<ValueConversion(GetType(SolidColorBrush), GetType(SolidColorBrush))> _
Public Class ColorConverter
Implements IValueConverter
Public Function Convert(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
Dim Color As Color = DirectCast(value, Color)
Return New SolidColorBrush(Color)
End Function
Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
Return Nothing
End Function
End Class
but all the examples I've seen bind it to the animation in XAML - And I'd like to do it in the code behind...
Can someone please point me in the right direction?
Thanks
The usual solution to this is not to use a converter, but instead to animate the Color of the Brush. However, to do this you need a PropertyPath, which in turn means you need a storyboard:
Storyboard s = new Storyboard();
s.Duration = new Duration(new TimeSpan(0, 0, 1));
s.Children.Add(F);
Storyboard.SetTarget(F, PulseLogo);
Storyboard.SetTargetProperty(F, new PropertyPath("Foreground.Color"));
s.Begin();
(pardon C# syntax)
Note the property path in the SetTargetProperty call, which traverses down through the Foreground property and into the resulting brush's Color property.
You can also use this technique to animate individual gradient stops in a gradient brush, etc.
ColorAnimation colorChangeAnimation = new ColorAnimation();
colorChangeAnimation.From = VariableColour;
colorChangeAnimation.To = BaseColour;
colorChangeAnimation.Duration = timeSpan;
PropertyPath colorTargetPath = new PropertyPath("(Panel.Background).(SolidColorBrush.Color)");
Storyboard CellBackgroundChangeStory = new Storyboard();
Storyboard.SetTarget(colorChangeAnimation, BackGroundCellGrid);
Storyboard.SetTargetProperty(colorChangeAnimation, colorTargetPath);
CellBackgroundChangeStory.Children.Add(colorChangeAnimation);
CellBackgroundChangeStory.Begin();
//VariableColour & BaseColour are class of Color, timeSpan is Class of TimeSpan, BackGroundCellGrid is class of Grid;
//no need to create SolidColorBrush and binding to it in XAML;
//have fun!

Resources