How to use Ribbon Buttons to execute code? - wpf

So far I have managed to create a ribbon with several buttons by following this tutorial.
Now I want to make the buttons actually do stuff! I found this example which shows how to execute already existing method. However if I do: Command="myCustomClass.myCustomMethod" and use
Class myCustomClass
Public Sub myCustomMethod()
'do stuff
End Sub
End Class
I get the error myCustomClass is not supported in a Windows Presentation Foundation (WPF) project.
I also noticed this this post from the same post. After converting the code to VB.NET:
Public Class MyCommand
Implements ICommand
Public Sub Execute(parameter As Object) Implements ICommand.Execute
Dim hello As String = TryCast(parameter, String)
MsgBox(hello)
End Sub
Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
Return True
End Function
Public Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged
End Class
and adding the references to the <Window x:Class="MainWindow" ... element:
<Window.Resources>
<local:MyCommand x:Key="mycmd"/>
</Window.Resources>
I get the following error: The name 'MyCommand' does not exist in the namespace "clr-namespace:RibbonSample".
I'm at a complete loss as to what I need to do to implement these buttons. Would it be possible to get any full ribbon samples using the same framework, with which I can learn from? I assume the solution to this should be really simple.

Rebuild your project.
The WPF designer loads classes from your project's compiled assembly (so that it can actually execute your code).
If you add a new class, it will give you errors until you rebuild your project so the assembly includes that class.

Related

WPF Custom Control VB.net

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

How to get all forms in a windows form application

I have a windows form application.
I want to get all of form that application has, but i just found about the function Application.OpenForms.
This function return all of forms are opening.
But I want to get all of forms in that application.
Is there any functions to get but not add to FormsColection for new Form created like this solution https://support.microsoft.com/en-us/kb/815707 ?
Thank you!
"All of the forms that an application has" typically would mean using reflection for all of the types in the assembly that inherit from the Windows.Forms.Form class.
The Application.OpenForms only tracks forms that are opened, not necessarily those that have been instantiated and not opened.
What you really need to do is track all of the forms when the form objects are instantiated. See code below:
Public Class Form1
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Globals.InstantiatedForms.Add(Me)
End Sub
End Class
Public Module Globals
Public InstantiatedForms As New List(Of Windows.Forms.Form)
End Module

WPF and VB.net: Data Binding to Separate Class created outside of Expression Blend

I have a WPF application with form that has a textbox named "txtStatusWindow". I also have a vb.net class handed to me by a co-worker that needs to be called and executed by the code in my application code-behind. My co-worker insists that I will need to use common .net events to update the textbox on my form.
The separate vb.net class:
Public Class globalclass
Public Event txtStatusWindow(ByVal Text As String)
Public Sub InitializeProgram()
RaiseEvent txtStatusWindow("Updating something.")
System.Threading.Thread.Sleep(2000)
RaiseEvent txtStatusWindow("Updating something else.")
System.Threading.Thread.Sleep(2000)
RaiseEvent txtStatusWindow("Updating something other than else.")
System.Threading.Thread.Sleep(2000)
RaiseEvent txtStatusWindow("Updating something other than the else stuff.")
System.Threading.Thread.Sleep(2000)
End Sub
End Class
I need to be able to call the sub "InitializeProgram()" from my code-behind, and it needs to be able to update "txtStatusWindow.text" as it runs.
I told him that the updating of the text box can be done with data-binding, but I don't know how to integrate a separate class like this into my project, how to call methods in it, or how to cause it to update my text blocks through data binding.
I also suggested that the methods in this class aren't optimal for connecting to the WPF project anyway, but he just wrote it as an example to discover how to connect the two projects.
Eventually, I will need to integrate classes like these that will be running separate threads to update their data from a dynamic source, and cause many controls to update in my application.
So far, the only way we have been able to get this to work from my code-behind is this:
Partial Public Class SplashScreen
Dim NewText as String
Public WithEvents Globals As globalclass = New globalclass
Public Delegate Sub StringDelegate(ByVal Text As String)
Public SplashText As String
Public Sub New()
MyBase.New()
Me.InitializeComponent()
Me.Show()
Globals.InitializeProgram()
End Sub
Public Sub UpdateSplashscreenHandler(ByVal Text As String) Handles Globals.UpdateSplashScreen
StatusWindowText.Text = Text
End Sub
Notwithstanding the fact that the WPF screen "freezes" until the "globalclass InitializeProgram" method completes (txtStatusWindow.Text does not update while sub without using the esoteric "refresh" extension...), I fully believe we are going about this the wrong way.
There are precious few examples out there concerning the integration and then binding to objects in existing code. Thanks for examining our little quandary.
If this status window is in XAML and the status window is a UserControl, then add a StatusText dependency property to the status window. Then, in the XAML you can bind to the value of that property with something like:
<UserControl x:Name="MyStatusWindow" ...>
<TextBlock Text="{Binding Path=StatusText, ElementName=MyStatusWindow}" />
</UserControl>
Then, from your event, just update the value of that StatusText property.
(Is that even close to what you were asking?)
Also, about that freezing: Instead of doing that updating in the constructor of that class, you might want to do it from the Loaded event of that control. It will still be freezing, though, unless you move it to a separate thread. Right now, that's happening on the same thread that the UI message pump is running on. This is the Dispatcher for that UI.

Basic WPF question: How to add a custom property trigger?

I am using Expresion Blend 3 and created a new user control in my project. I want a storyboard to run if a custom property of that user control is triggered like with the ones shown here in the list..
I learnt you need a dependency property, but my understanding there is limited. Here's the basic code I set up with property "IsAwesome" as an example..
Partial Public Class simpleControl
Public Sub New()
MyBase.New()
Me.InitializeComponent()
End Sub
Public Shared ReadOnly IsAwesomeProperty As DependencyProperty = _
DependencyProperty.Register("IsAwesome", GetType(Boolean), GetType(simpleControl))
Public Property IsAwesome() As Boolean
Get
Return DirectCast(Me.GetValue(IsAwesomeProperty), Boolean)
End Get
Set(ByVal value As Boolean)
Me.SetValue(IsAwesomeProperty, value)
End Set
End Property
End Class
However, my property doesn't show in that list. What am I missing? Or is my entire approach wrong?
Any help or advice would be appreciated!
Cheers
I created a new Wpf project. Added a new UserControl (UserControl1) with a custom dependency property called Foo.
Then I opened Blend and added an instance of UserControl1 to Window1. I right clicked on UserControl1 and said EditTemplate | Edit a Copy.
This created a copy of my user control template in the Window.Resources. From within this new template I went up to the Triggers panel and clicked the button to add a new property trigger.
Right away Blend defaulted to selecting my property in the "Activated When" section.
alt text http://blog.BradCunningham.net/Images/ForumImages/CustomDPInBlend.png
You can grab my little sample app from here: http://blog.BradCunningham.net/SourceCode/ForumSamples/CustomDPInBlend.zip

Is there an event that triggers if the number of ListViewItems in a ListView changes? (Windows Forms)

I'd like to enable/disable some other controls based on how many items are in my ListView control. I can't find any event that would do this, either on the ListView itself or on the ListViewItemCollection. Maybe there's a way to generically watch any collection in C# for changes?
I'd be happy with other events too, even ones that sometimes fire when the items don't change, but for example the ControlAdded and Layout events didn't work :(.
#Domenic
Not too sure, Never quite got that far in the thought process.
Another solution might be to extend ListView, and when adding and removing stuff, instead of calling .items.add, and items.remove, you call your other functions. It would still be possible to add and remove without events being raised, but with a little code review to make sure .items.add and .items.remove weren't called directly, it could work out quite well. Here's a little example. I only showed 1 Add function, but there are 6 you would have to implement, if you wanted to have use of all the available add functions. There's also .AddRange, and .Clear that you might want to take a look at.
Public Class MonitoredListView
Inherits ListView
Public Event ItemAdded()
Public Event ItemRemoved()
Public Sub New()
MyBase.New()
End Sub
Public Function AddItem(ByVal Text As String) As ListViewItem
RaiseEvent ItemAdded()
MyBase.Items.Add(Text)
End Function
Public Sub RemoveItem(ByVal Item As ListViewItem)
RaiseEvent ItemRemoved()
MyBase.Items.Remove(Item)
End Sub
End Class
I can't find any events that you could use. Perhaps you could subclass ListViewItemCollection, and raise your own event when something is added, with code similar to this.
Public Class MyListViewItemCollection
Inherits ListView.ListViewItemCollection
Public Event ItemAdded(ByVal Item As ListViewItem)
Sub New(ByVal owner As ListView)
MyBase.New(owner)
End Sub
Public Overrides Function Add(ByVal value As System.Windows.Forms.ListViewItem) As System.Windows.Forms.ListViewItem
Dim Item As ListViewItem
Item = MyBase.Add(value)
RaiseEvent ItemAdded(Item)
Return Item
End Function
End Class
I think the best thing that you can do here is to subclass ListView and provide the events that you want.

Resources