Can anyone see the simple mistake that I can't?
I am opening a form to allow assigning Job Numbers to invoices that do not have any.
This is the code in the applications main form that handles this:
Dim unknownJobs = From pur In context.Purchases
Where pur.SentToMyob = False AndAlso
pur.Job.JobNumber = String.Empty
Select pur
If unknownJobs.Any Then
frmJobs2.JobsBindingSource.DataSource = (From j In context.Jobs1
Order By j.JobNumber
Select j).ToList
frmJobs2.PurchasesBindingSource.DataSource = unknownJobs
Progress.Hide()
If frmJobs2.ShowDialog = Windows.Forms.DialogResult.OK Then
context.SaveChanges()
End If
End If
This is the Form that gets opened with the relevant column details displayed
The Code behind is simple and consists of:
Public Class FormJobs2
''' <summary>
''' OK clicked
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub OKButton_Click(sender As System.Object, e As System.EventArgs) Handles OKButton.Click
Me.DialogResult = Windows.Forms.DialogResult.OK
Me.Close()
End Sub
''' <summary>
''' Cancel clicked
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub SkipButton_Click(sender As System.Object, e As System.EventArgs) Handles SkipButton.Click
Me.DialogResult = Windows.Forms.DialogResult.Cancel
Me.Close()
End Sub
End Class
What happens when it runs is that you can select the job numbers BUT they do not display on the DataGridView and do not update the underlying context.
Where is the stupid mistake, please?
It appears as if you are trying to assign your frmJobs2.PurchasesBindingSource.DataSource an IQueryable.
The line should read:
frmJobs2.PurchasesBindingSource.DataSource = unknownJobs.ToList
Related
I've been developing a wpf user control as a means of increasing my own knowledge and also because it will be of use to me in later projects. Essentially it's a data navigator control looking not dissimilar to the image below.
Each button has a default image associated with it which the end user can replace if they so wish, achieved with the following code;
Private Shared ReadOnly DefaultFirstImage As ImageSource = New BitmapImage(New Uri("pack://application:,,,/DataNavigator;component/Images/first16.png", UriKind.RelativeOrAbsolute))
'''////////////////////////////////////////////////////////////////////////////////////////////////////
''' <summary> Gets or sets the image first. </summary>
'''
''' <value> The image first. </value>
'''////////////////////////////////////////////////////////////////////////////////////////////////////
<Description("The image used to represent navigating to the first record in the records collection"), Category("Navigation Button Images")>
Public Property ImageFirst() As ImageSource
Get
Return DirectCast(GetValue(ImageFirstProperty), ImageSource)
End Get
Set(value As ImageSource)
SetValue(ImageFirstProperty, value)
End Set
End Property
''' <summary> The image first property. </summary>
Public Shared ReadOnly ImageFirstProperty As DependencyProperty = DependencyProperty.Register("ImageFirst", GetType(ImageSource), GetType(DataNavigator), New UIPropertyMetadata(DefaultFirstImage))
The navigation buttons also have a text property which by default is set to an empty string but which can be customised by the end user.
Now I'd like to add one last customisation to this, give the end user the freedom to have no default image at all and simply text instead. I'm thinking along the lines of a Boolean dependency property (lets say called RemoveFirstButtonImage ) with a default value of false which when checked would remove the image and set some default text instead.
I've done some playing about....
Public Shared ReadOnly RemoveDefaultFirstImageProperty As DependencyProperty = DependencyProperty.Register("RemoveDefaultFirstImage", GetType(Boolean), GetType(DataNavigator), New FrameworkPropertyMetadata(False, FrameworkPropertyMetadataOptions.AffectsRender, New PropertyChangedCallback(AddressOf OnRemoveDefaultFirstImageChanged)))
'''////////////////////////////////////////////////////////////////////////////////////////////////////
''' <summary>
''' Gets or sets a value indicating whether the hide Template button is
''' shown.
''' </summary>
'''
''' <value> true if show hide Template button, false if not. </value>
'''////////////////////////////////////////////////////////////////////////////////////////////////////
<Description("Set the visibility of the Template button on the Navigator Control"), Category("Navigator Buttons Default Image Visibility")>
Public Property RemoveDefaultFirstImage As Boolean
Get
Return CBool(GetValue(RemoveDefaultFirstImageProperty))
End Get
Set(ByVal value As Boolean)
SetValue(RemoveDefaultFirstImageProperty, value)
End Set
End Property
Private Shared Sub OnRemoveDefaultFirstImageChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
Dim dn As DataNavigator = CType(d, DataNavigator)
Dim bln As Boolean = (CType(e.NewValue, Boolean))
If bln Then
dn.DefaultFirstImage = New BitmapImage(New Uri("pack://application:,,,/DataNavigator;component/Images/first16.png", UriKind.RelativeOrAbsolute))
Else
DataNavigator.DefaultFirstImage = Nothing
End If
End Sub
However there is an issue with the definition of the DefaultFirstImage Property.
Clearly it should no longer be shared and I suspect it should be public and have both a setter and getter but is this all that needs to be done to achieve my desired result (I've left out adding default text but That's easy enough) or is there something else that I may have overlooked?
Thanks
I am trying for MVVM pattern basic level and got struck at ICommand CanExecute changed. I have XAML binding as follows:
<ListBox ItemsSource="{Binding Contact.Addresses}" x:Name="AddressCollections" Height="152" SelectedValue="{Binding SelectedAddress}"
DockPanel.Dock="Top" />
<Button Content="Add" Command="{Binding AddAddressCommand}" DockPanel.Dock="Top" />
<Button Content="Remove" Command="{Binding DeleteAddressCommand}" DockPanel.Dock="Bottom" />
Commands:
Public Class DeleteCommand
Implements ICommand
Private method As Object
Private methodname As String
Public Sub New(ByVal Controlname As String, ByVal mee As Object)
methodname = Controlname
method = mee
End Sub
Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
Select Case methodname
Case "Address"
Return TryCast(method, ModelView.Contacts.ContactMV).CanDeleteAddress()
Case "Numbers"
Return TryCast(method, ModelView.Contacts.ContactMV).CanDeleteNumbers
Case Else : Return False
End Select
End Function
Public Event CanExecuteChanged(sender As Object, e As EventArgs) Implements ICommand.CanExecuteChanged
Public Sub Execute(parameter As Object) Implements ICommand.Execute
Select Case methodname
Case "Address"
TryCast(method, ModelView.Contacts.ContactMV).DeleteAddress()
Case "Numbers"
TryCast(method, ModelView.Contacts.ContactMV).DeleteNumbers()
Case Else
End Select
End Sub
End Class
My ModelView:
Public Class ContactMV
Property Contact As Model.Contacts.ContactMod
Property AddAddressCommand As New Commands.AddCommand("Address", Me)
Property DeleteAddressCommand As New Commands.DeleteCommand("Address", Me)
Property SelectedAddress As Model.Contacts.AddressModel
Public Sub AddAddress()
If Contact.Addresses.Count = 0 Then
Contact.Addresses.Add(New Model.Contacts.AddressModel(Contact.Primary.ID, True))
Else
Contact.Addresses.Add(New Model.Contacts.AddressModel(Contact.Primary.ID, False))
End If
End Sub
Public Sub DeleteAddress()
If IsNothing(SelectedAddress) = False Then
Try
Contact.Addresses.Remove(SelectedAddress)
Catch ex As Exception
MsgBox("Address not found")
End Try
End If
End Sub
Public Function CanDeleteAddress()
If IsNothing(SelectedAddress) Then
Return False
Else
Return Contact.Addresses.Contains(SelectedAddress)
End If
End Function
End Class
The problem is that the Canexecutechanged is firing only at start, I actually want to get the delete button enabled only when something in the listbox is selected, and I want to get it done by MVVM - ICommand binding method. Could you please explain where i went wrong or miss understood the ICommand implementation.
Thank you.
Updated Relay iCommand code I use:
Public Class RelayCommand
Implements ICommand
''' <summary>
''' A command whose sole purpose is to relay its functionality to other objects by invoking delegates. The default return value for the CanExecute method is 'true'.
''' </summary>
''' <remarks></remarks>
#Region "Declarations"
Private ReadOnly _CanExecute As Func(Of Boolean)
Private ReadOnly _Execute As Action
#End Region
#Region "Constructors"
Public Sub New(ByVal execute As Action)
Me.New(execute, Nothing)
End Sub
Public Sub New(ByVal execute As Action, ByVal canExecute As Func(Of Boolean))
If execute Is Nothing Then
Throw New ArgumentNullException("execute")
End If
_Execute = execute
_CanExecute = canExecute
End Sub
#End Region
#Region "ICommand"
Public Custom Event CanExecuteChanged As EventHandler Implements System.Windows.Input.ICommand.CanExecuteChanged
AddHandler(ByVal value As EventHandler)
If _CanExecute IsNot Nothing Then
AddHandler CommandManager.RequerySuggested, value
End If
End AddHandler
RemoveHandler(ByVal value As EventHandler)
If _CanExecute IsNot Nothing Then
RemoveHandler CommandManager.RequerySuggested, value
End If
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
'This is the RaiseEvent block
'CommandManager.InvalidateRequerySuggested()
End RaiseEvent
End Event
Public Function CanExecute(ByVal parameter As Object) As Boolean Implements System.Windows.Input.ICommand.CanExecute
If _CanExecute Is Nothing Then
Return True
Else
Return _CanExecute.Invoke
End If
End Function
Public Sub Execute(ByVal parameter As Object) Implements System.Windows.Input.ICommand.Execute
_Execute.Invoke()
End Sub
#End Region
End Class
Most of the code is a copy, but I understood the working by below comments.
As Raul OtaƱo has pointed out, you can raise the CanExecuteChanged. However, not all MVVM frameworks provide a RaiseCanExecuteChanged method. It's also worth noting that the actual event CanExecuteChanged must be called on the UI thread. So, if you're expecting a callback from some thread in your model, you need to invoke it back to the UI thread, like this:
public void RaiseCanExecuteChanged()
{
if (CanExecuteChanged != null)
{
Application.Current.Dispatcher.Invoke((Action)(() => { CanExecuteChanged(this, EventArgs.Empty); }));
}
}
I would very much recommend against calling CommandManager.InvalidateRequerySuggested() because although this works functionally, and is ok for small applications, it is indiscriminate and will potentially re-query every command! In a large system with lots of commands, this can be very very slow!
You must have in your ICommand implementation some method like RaiseCanExecuteChanged that fires the event CanExecuteChanged. Then every time that the selected item in the list changed, in your view model you execute the RaiseCanExecuteChanged from the command you want. Any way I suggest you to use any generic command, like the RelayCommand of GalaSoft MVVMLite library, or any implementation of DelegateCommand.
Hope this helps...
I'm using Linq to SQL classes in my WCF. Those classes are returned from the WCF methods to the Silverlight. Now, I want to add a custom property on a the generated class (Silverlight side) and trigger a PropertyChangedEvent on that particular property, based on another PropertyChangedEvent from another property. To be clear, here's a piece of code that doesn't work :
Partial Public Class DataConnection
Public Sub New()
AddHandler Me.PropertyChanged, AddressOf _PropertyChanged
End Sub
Private Sub _PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs)
If e.PropertyName = "ConnectionType" Then
Me.RaisePropertyChanged("ConnectionTypeEnum")
End If
End Sub
Private _ConnectionTypeEnum As String
Public ReadOnly Property ConnectionTypeEnum() As String
Get
Select Case Me.ConnectionType
Return //Something based on ConnectionType //
End Select
End Get
End Property
End Class
The problem is that the code in New() is never executed, so I never know when the ConnectionType is changed, so I can't trigger the PropertyChanged on ConnectionTypeEnum. (this property is used a in One-Way binding so I need it)
Does anyone have a solution for this ?
Thanks
You can use OnDeserializedAttribute
<OnDeserializedAttribute()> _
Public Sub WhenDeserialized(context As StreamingContext)
AddHandler Me.PropertyChanged, AddressOf _PropertyChanged
End Sub
I created a usercontrol with a treeview inside it. The treeview will be populated if I add nodes in the onload handler of the usercontrol. But after that(for example, I click a button in its parent form), the treeview will not refresh. I can see the nodes was updated in memory, but it just cannot display on the screen. I called refresh/update after adding nodes. Any suggestion is appreciated.
I put a quick test together based on your description and it seems to paint just fine.
UserControl1
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class UserControl1
Inherits System.Windows.Forms.UserControl
'UserControl overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Me.TreeView1 = New System.Windows.Forms.TreeView
Me.SuspendLayout()
'
'TreeView1
'
Me.TreeView1.Dock = System.Windows.Forms.DockStyle.Fill
Me.TreeView1.Location = New System.Drawing.Point(0, 0)
Me.TreeView1.Name = "TreeView1"
Me.TreeView1.Size = New System.Drawing.Size(150, 150)
Me.TreeView1.TabIndex = 0
'
'UserControl1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.Controls.Add(Me.TreeView1)
Me.Name = "UserControl1"
Me.ResumeLayout(False)
End Sub
Friend WithEvents TreeView1 As System.Windows.Forms.TreeView
End Class
Public Class UserControl1
Public Sub AddNewNode(ByVal text As System.String)
TreeView1.Nodes.Add(text)
End Sub
End Class
Put the usercontrol on a form with a button
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
UserControl11.AddNewNode(Now.ToString)
End Sub
End Class
If you are seeing proper painting as well then look at any graphics handling in the parent form then the usercontrol then the controls within the usercontrol. We really need more info.
Thank you, Dave. I figured it out. I put the usercontrol twice to my form by mistake(I cannot remember how I did it). And the one I operate is underneath the other one. That's why I cannot see it. Sorry for wasting your time.
I have a datagrid bound to an observable collection of objects. What I want to do is have a button that will execute a method of the object representing the row of the button that was clicked. So what I have now is something like this:
<DataGridTemplateColumn Header="Command">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Name="cmdCommand" Click="{Binding Command}"
Content="Command"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Which doesn't work and reports the following error:
Click="{Binding Command}" is not valid. '{Binding Command}' is not a valid event handler method name. Only instance methods on the generated or code-behind class are valid.
I've looked at command binding but that looks like it would just end up going to a single external command instead of to the object bound to the row. I have it working using an event handler on the code behind and then routing it to the item bound to the selected row (since the row gets selected when the button is clicked) but that seems like poor way of handing this and I assume I'm just missing something here.
I do this all the time. Here's a look at an example and how you would implement it.
Change your XAML to use the Command property of the button instead of the Click event. I am using the name SaveCommand since it is easier to follow then something named Command.
<Button Command="{Binding Path=SaveCommand}" />
Your CustomClass that the Button is bound to now needs to have a property called SaveCommand of type ICommand. It needs to point to the method on the CustomClass that you want to run when the command is executed.
public MyCustomClass
{
private ICommand _saveCommand;
public ICommand SaveCommand
{
get
{
if (_saveCommand == null)
{
_saveCommand = new RelayCommand(
param => this.SaveObject(),
param => this.CanSave()
);
}
return _saveCommand;
}
}
private bool CanSave()
{
// Verify command can be executed here
}
private void SaveObject()
{
// Save command execution logic
}
}
The above code uses a RelayCommand which accepts two parameters: the method to execute, and a true/false value of if the command can execute or not. The RelayCommand class is a separate .cs file with the code shown below. I got it from Josh Smith :)
/// <summary>
/// A command whose sole purpose is to
/// relay its functionality to other
/// objects by invoking delegates. The
/// default return value for the CanExecute
/// method is 'true'.
/// </summary>
public class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
/// <summary>
/// Creates a new command that can always execute.
/// </summary>
/// <param name="execute">The execution logic.</param>
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameters)
{
return _canExecute == null ? true : _canExecute(parameters);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameters)
{
_execute(parameters);
}
#endregion // ICommand Members
}
You have various possibilies. The most simple and the most ugly is:
XAML
<Button Name="cmdCommand" Click="Button_Clicked" Content="Command"/>
Code Behind
private void Button_Clicked(object sender, RoutedEventArgs e) {
FrameworkElement fe=sender as FrameworkElement;
((YourClass)fe.DataContext).DoYourCommand();
}
Another solution (better) is to provide a ICommand-property on your YourClass. This command will have already a reference to your YourClass-object and therefore can execute an action on this class.
XAML
<Button Name="cmdCommand" Command="{Binding YourICommandReturningProperty}" Content="Command"/>
Because during writing this answer, a lot of other answers were posted, I stop writing more. If you are interested in one of the ways I showed or if you think I have made a mistake, make a comment.
Here is the VB.Net rendition of Rachel's answer above.
Obviously the XAML binding is the same...
<Button Command="{Binding Path=SaveCommand}" />
Your Custom Class would look like this...
''' <summary>
''' Retrieves an new or existing RelayCommand.
''' </summary>
''' <returns>[RelayCommand]</returns>
Public ReadOnly Property SaveCommand() As ICommand
Get
If _saveCommand Is Nothing Then
_saveCommand = New RelayCommand(Function(param) SaveObject(), Function(param) CanSave())
End If
Return _saveCommand
End Get
End Property
Private _saveCommand As ICommand
''' <summary>
''' Returns Boolean flag indicating if command can be executed.
''' </summary>
''' <returns>[Boolean]</returns>
Private Function CanSave() As Boolean
' Verify command can be executed here.
Return True
End Function
''' <summary>
''' Code to be run when the command is executed.
''' </summary>
''' <remarks>Converted to a Function in VB.net to avoid the "Expression does not produce a value" error.</remarks>
''' <returns>[Nothing]</returns>
Private Function SaveObject()
' Save command execution logic.
Return Nothing
End Function
And finally the RelayCommand class is as follows...
Public Class RelayCommand : Implements ICommand
ReadOnly _execute As Action(Of Object)
ReadOnly _canExecute As Predicate(Of Object)
Private Event ICommand_CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged
''' <summary>
''' Creates a new command that can always execute.
''' </summary>
''' <param name="execute">The execution logic.</param>
Public Sub New(execute As Action(Of Object))
Me.New(execute, Nothing)
End Sub
''' <summary>
''' Creates a new command.
''' </summary>
''' <param name="execute">The execution logic.</param>
''' <param name="canExecute">The execution status logic.</param>
Public Sub New(execute As Action(Of Object), canExecute As Predicate(Of Object))
If execute Is Nothing Then
Throw New ArgumentNullException("execute")
End If
_execute = execute
_canExecute = canExecute
End Sub
<DebuggerStepThrough>
Public Function CanExecute(parameters As Object) As Boolean Implements ICommand.CanExecute
Return If(_canExecute Is Nothing, True, _canExecute(parameters))
End Function
Public Custom Event CanExecuteChanged As EventHandler
AddHandler(ByVal value As EventHandler)
AddHandler CommandManager.RequerySuggested, value
End AddHandler
RemoveHandler(ByVal value As EventHandler)
RemoveHandler CommandManager.RequerySuggested, value
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As EventArgs)
If (_canExecute IsNot Nothing) Then
_canExecute.Invoke(sender)
End If
End RaiseEvent
End Event
Public Sub Execute(parameters As Object) Implements ICommand.Execute
_execute(parameters)
End Sub
End Class
Hope that helps any VB.Net developers!
Click is an event. In your code behind, you need to have a corresponding event handler to whatever you have in the XAML. In this case, you would need to have the following:
private void Command(object sender, RoutedEventArgs e)
{
}
Commands are different. If you need to wire up a command, you'd use the Commmand property of the button and you would either use some pre-built Commands or wire up your own via the CommandManager class (I think).
On Xamarin Forms, the ugliest and most straightforward version:
Xaml:
<Button Margin="0,10,0,0"
Text="Access galery"
Clicked="OpenGalery"
BackgroundColor="{StaticResource Primary}"
TextColor="White" />
then: in .cs
private async void OpenGalery(object sender, EventArgs e)
{
//do your bidding
}