How to make checkbox trigger a command when checked? - c#

I have a checkbox and a [RelayCommand] in the viewmodel that I want to link it to so that the command runs when the checkbox is ticked/unticked (ideally knowing the state of the checkbox as well) but I cannot seem to do it.
<CheckBox Grid.Column="1"
Grid.RowSpan="2"
Color="DarkGreen"
Scale="1.2">
<CheckBox.Behaviors>
<toolkit:EventToCommandBehavior
EventName="CheckedChanged"
Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:AdvanceViewModel}}, Path=CheckAnswerCommand}"
CommandParameter="{Binding MarksFromPoint}" />
</CheckBox.Behaviors>
</CheckBox>
This is what I have tried currently but it gives me a System Exception: "Operation is not valid due to the current state of the object".
How do I make it work in the way I want.
I am using .NET 7 and using MAUI for the app. I have the Maui Community Toolkit in use as well.
Any help is appreciated.

I can replicate your issue and there's a Command is missing on Checkbox control #7394 on Github, you can follow up there.
Also, you can refer to EventToCommandBehavior throws InvalidOperationException in MAUI for checkbox which may provide a workaround to fix it.

Related

1 Control, two separate binding sources

Good Morning!
I have a WPF application that will display a number of different file types based on command line args it receives. It works fine, but I want to go back and refactor it. I have only been a developer for a few years and would like to master MVVM.
I am using an MVVM design package called Stylet. In my PDF view I am using a Telerik RadPdfViewer control to which Telerik has all this binding stuff built in for you. For example, I am binding the right click context menu with the commands "select all" and "copy" using their pre configured command bindings.
I would like to bind the "Document Source" property TO MY viewmodel so I can pass in the paths of documents I want to load. However, the DataContext of the control is bound to Telerik's CommandDescriptors preventing the binding to my viewmodel.
<telerik:RadPdfViewer x:Name="radPdfViewer" Grid.Row="1"
DataContext="{Binding CommandDescriptors, ElementName=radPdfViewer}"
DocumentSource="{Binding PDFDoc}"
telerik:RadPdfViewerAttachedComponents.RegisterFindDialog="True"
HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Stretch"
telerik:StyleManager.Theme="Office_Black" Grid.ColumnSpan="2">
<telerik:RadContextMenu.ContextMenu>
<telerik:RadContextMenu>
<telerik:RadMenuItem Header="Select All"
Command="{Binding SelectAllCommandDescriptor.Command}" />
<telerik:RadMenuItem Header="Copy"
Command="{Binding CopyCommandDescriptor.Command}" />
</telerik:RadContextMenu>
</telerik:RadContextMenu.ContextMenu>
</telerik:RadPdfViewer>
public class PDFViewModel
{
private string _pdfDoc;
public string PDFDoc
{
get
{
return _pdfDoc;
}
set
{
_pdfDoc = value;
}
}
public PDFViewModel()
{
PDFDoc = #"t:\share\large.pdf";
}
}
I see two choices
I break Telerik's prebuilt command bindings and figure out how to bring the select all and copy functions to my viewmodel.
Stylet has an s:Action function where I can call a method where I can load the document into the RadPdfViewer control using C#. I would need to somehow get control of the gui control in the method of my viewmodel and I am not sure how to do that.
Is there a better way? A little nudge in the right direction would be greatly appreciated.
Jason Tyler's reply got me going in the right direction. Thank you!
So because I am using a ViewModel first pattern, I did not need to specify the DataContext of the user control like I thought...Its already set.
However, his suggestion of binding using the relative source and researching on how to do this (I have never used RelativeSource before..I am kinda new to this stuff) I came across this Stack post
How do I use WPF bindings with RelativeSource?
A Jeff Knight Posted a diagram of how ancestor binding works.
Using that, I was able to figure out the syntax and my document came right up and I can still use the right click context menu items that are bound to Telerik. So now my Xaml looks like this note how the Document source binding has changed.
<telerik:RadPdfViewer x:Name="radPdfViewer" Grid.Row="1"
DataContext="{Binding CommandDescriptors, ElementName=radPdfViewer}"
DocumentSource="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DataContext.PDFDoc}"
telerik:RadPdfViewerAttachedComponents.RegisterFindDialog="True"
HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Stretch"
telerik:StyleManager.Theme="Office_Black" Grid.ColumnSpan="2">
<telerik:RadContextMenu.ContextMenu>
<telerik:RadContextMenu>
<telerik:RadMenuItem Header="Select All"
Command="{Binding SelectAllCommandDescriptor.Command}" />
<telerik:RadMenuItem Header="Copy"
Command="{Binding CopyCommandDescriptor.Command}" />
</telerik:RadContextMenu>
</telerik:RadContextMenu.ContextMenu>
</telerik:RadPdfViewer>

UWP ButtonColumn MvvmLight / Telerik / WindowsTemplate Studio

I´m trying to add a ButtonColumn to a TelerikDataGrid which was generated by the Windows Template Studio, without CodeBehind.
In a perfect world it would work like this, I think.
<tg:DataGridTemplateColumn x:Uid="Table_Open" >
<tg:DataGridTemplateColumn.CellContentTemplate >
<DataTemplate>
<Button x:Uid="Button_Open" Command="{x:Bind ViewModel.OpenCustomerCommand}"></Button>
</DataTemplate>
</tg:DataGridTemplateColumn.CellContentTemplate>
</tg:DataGridTemplateColumn>
This doesn't work, now I tried many opportunities but never reach the ViewModel.
I know in WPF it would work using
RelativeSource={RelativeSource AncestorType={x:Type UserControl},
But I don't get it reproduced in my UWP case.
I'm afraid you can't use x:bind to bind OpenCustomerCommand in DataTemplate, In general, if we want to bind viewmodel's OpenCustomerCommand we need set current Page DataContext as ViewModel then use binding markup extension to bind like the following.
<Button HorizontalAlignment="Right"
Margin="0,0,30,0"
Content="Favorite"
Command="{Binding ElementName=RootGrid,Path=DataContext.OpenCustomerCommand }"
/>
And this is the similar case that your could refer.

InvalidOperationException when hiding/showing columns in a WPF DataGrid

I have a DataGrid and I want the user to be able to show/hide columns on it.
I have a button that will show/hide a specific column, and it works fine on one (fast, graphics card, .NET 4.5) machine but not on a different (slow, no graphics hardware, .NET 4.0) machine.
The InvalidOperationException is thrown when hiding then showing the same column... Note that multiple columns can be turned off (by setting their Visiblity to Collapsed), but as soon as one that is already off is turned back on (setting Visibility to Visible) the application crashes and throws the exception.
Looking at the Event Viewer, the exception is being thrown in the DataGrid's AddLogicalChild method, which calls ChangeLogicalParent (I'm assuming on the column being added- note I cannot debug this with breakpoints as the machine I am running it on does not have Visual Studio installed)
Any ideas on what could be causing the app to throw the exception on one machine but not another? Any chance that the .NET runtime has anything to do with it? (upgrading to .NET 4.5 on the machine running the app may not be feasible)
i use the following code to show/hide columns
<DataGrid ItemsSource="{Binding MyView}">
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="Show/ Hide">
<StackPanel>
<ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.Columns, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type DataGridColumn}">
<CheckBox Content="{Binding Path=Header, Mode=OneWay}"
IsChecked="{Binding Path=Visibility, Converter={StaticResource TrueIfVisibleConverter}}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</MenuItem>
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
TrueIfVisibleConverter simply set true to visible and false to collapsed.
Believe it or not... updating the .NET version from 4.0 to 4.5 fixed the problem!

Calling a command in my ViewModel from a binding to an event in my XAML?

I am currently writing a Windows 8 application. I am trying to call a method in my ViewModel. I want this method to be called when an item is double clicked. I have defined the following DataTemplate in my XAML to do this:
<DataTemplate x:Key="ItemTemplate">
<StackPanel Orientation="Horizontal">
<Image Width="185" Height="185" Stretch="Fill" Source="{Binding Path=Image}" DoubleTapped="{Binding Path=MethodIWishToBindTo}" IsDoubleTapEnabled="True" />
</StackPanel>
</DataTemplate>
The problem, of course, is the error message for my binding to MethodIWishToBindTo:
Invalid value for 'DoubleTapped'. Event values must be text
What is the best way for me to get around this ? I could call the method in the code-behind, however the method uses a property in my ViewModel, "SelectedItemInList", which I don't believe can be accessed from the code behind.
Can anyone offer me some advice for this problem ?
Thanks a lot.
You could use Interactivity and a custom behavior to trigger the event. Here's a post that topically covers an example:
MVVM-Light EventToCommand Behavior for CheckBox Checked/Unchecked in Silverlight
MVVM-Light definitely makes this easier, but it's possible without as well.
Here's an example of without: http://blog.roboblob.com/2010/01/26/binding-ui-events-from-view-to-commands-in-viewmodel-in-silverlight-4/

OneWayToSource in Silverlight and UpdateSource issue

I'm facing some problems binding a CommandParameter to its own Command in an application built using Prism 2.2 as MVVM . Let me introduce what it's happening.
I've got a customized listbox with a property named NumPageElements, and a couple of buttons to scroll through the list who needs that property. A simplified xaml of what I need (and works) in wpf is:
<Button x:Name="PageDownButton" Command="{Binding PageDownCommand}" CommandParameter="{Binding ElementName=ItemsListBox, Path=NumPageElements}" />
<Custom:MyOwnListBox x:Name="ItemsListBox" x:NumPageElements="{Binding ElementsPerPage, Mode=OneWayToSource}" >
. . .
</Custom:MyOwnListBox>
To have the same behaviour in Silverlight I wrote this xaml:
<Button Name="PageDownButton" Command="{Binding PageDownCommand}" CommandParameter="{Binding ElementName=ItemsListBox, Path=NumPageElements}" />
<Custom:MyOwnListBox Name="ItemsListBox" NumPageElements="{Binding Path=ElementsPerPage, Mode=TwoWay, UpdateSourceTrigger=Explicit}" >
. . .
</Custom:MyOwnListBox>
PageDownButton is an IApplicationCommand, ElementsPerPage is a property exposed by the presenter.
Now, the first time I open this view the buttons made in that way look enabled but they aren't 'clickable'. If I switch to a different view and I go back to the view with those button, they finally catch the correct behavior. It looks like it doesn't initialize correctly the first time the condition of the command (infact they should be disabled until I insert an item in the listbox), as if the parameter given via the CommandParameter property isn't initiliazed correctly. But I can't understand why switching between the views make it works.
I suspected I should force the UpdateSource of the bindings (I did it for ItemsListBox.NumPageElements and for PageDownButton.CommandParameter) after the view has been loaded, but doing it in the code behind was not of any help.
What I am doing wrong?
Thanks for any reply,
Mat.

Categories