I want to use a delegate command with a Horizontaltoggleswitch that is fired when the switch is toggled. I use delegate commands with button and also with textboxes (where the Event is fired when the enterkey is pressed), but I cant find how to solve that with toggleswitch? I tried this:
XAML:
<toggleSwitch:HorizontalToggleSwitch CheckedContent="Open" UncheckedContent="Closed" IsChecked="{Binding SubstrateValveOpen,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<toggleSwitch:HorizontalToggleSwitch.InputBindings>
<KeyBinding Command="{Binding SubstrateCommand}" Key="??"/>
</toggleSwitch:HorizontalToggleSwitch.InputBindings>
</toggleSwitch:HorizontalToggleSwitch>
ViewModel:
private bool _substrateValveOpen;
public bool SubstrateValveOpen
{
get => _substrateValveOpen;
set => SetProperty(ref _substrateValveOpen, value);
}
public DelegateCommand SubstrateCommand => new DelegateCommand(Substrate, CanSubstrate);
...
but I dont really know what to do with the Event.
thanks for any idea!
The command is completely superfluous here. The property should do everything here.
Reminder: a property ist not just a field with PropertyChanged...
private bool _substrateValveOpen;
public bool SubstrateValveOpen
{
get => _substrateValveOpen;
set
{
if (value && !_substrateValveOpen && !CanSubstrate())
return;
if (SetProperty(ref _substrateValveOpen, value) && value)
Substrate();
}
}
Related
I have two menu items, "message", and "check". "Check" is Checkable and have a checkbox near the header. I want, by clicking on Check to uncheck it, and disable the "message" item.
Also, I want to do it by both clicking, and using a shortcut.
I wrote some additional classes like RelayCommand
public class RelayCommand : ICommand
{
private Action<object> _execute;
private Func<object, bool> _canExecute;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
_canExecute = canExecute;
_execute = execute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
Observable object (which is analogue of INotifyOnPropertyChanged)
public class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
and MainViewModel class
public class MainViewModel : ObservableObject
{
private readonly MainWindow _mainWindow;
private bool _isChecked { get; set; } = true;
public bool IsChecked
{
get
{
return _isChecked;
}
set
{
_isChecked = value;
OnPropertyChanged();
}
}
public RelayCommand Check { get; set; }
public MainViewModel(MainWindow mainwindow)
{
_mainWindow = mainwindow;
IsChecked = false;
Check = new RelayCommand(o =>
{
if (IsChecked == false)
{
_mainWindow.Message_menu_item.IsEnabled = true;
IsChecked = true;
}
else
{
_mainWindow.Message_menu_item.IsEnabled = false;
IsChecked = false;
}
});
}
}
My xaml
<MenuItem Header="File">
<MenuItem
Name="Message_menu_item"
InputGestureText="Ctrl+M"
Header="_Message"/>
<MenuItem
Name="Check_menu_item"
InputGestureText="Ctrl+C"
Command="{Binding Check}"
Header="Check"
IsCheckable="True"
IsChecked="{Binding IsChecked}"/>
<Separator />
<MenuItem Header="Exit"
InputGestureText="Ctrl+E"/>
</MenuItem>
And binding
<KeyBinding Key="C" Modifiers="Ctrl" Command="{Binding Check}"/>
I wanted to start an app with checked checkbox and available Message menu item, but it is starting unchecked, and by clicking it, it simply disabling the message, and ignoring the checkbox (it only work ones, clicking on it again doesn't change anything). It only works fine using the shortcut, BUT I can only use shortcut after clicking the menu dropdown button "file" in my case (like this, and if it is closed shortcut doesn't work )
I don't understand why is it working so weird, please help.
I wanted to start an app with checked checkbox
If so, you should change the initialization IsChecked = false; in your viewmodel constructor accordingly.
The weird behaviour of the checkbox is a result of modifying IsChecked from the Check command plus binding it to the IsChecked property of the menu item without specifying a mode (which results in a two way binding). So, when using the menu, the property is toggled twice: via command and via the binding. Using the key binding works, because it only triggers the command.
To solve this, either change the binding mode to OneWay or don't change the property value in the command.
Furthermore: You should remove the reference to the window from your viewmodel. This can be achieved by binding the IsEnabled property of the message menu item to another property on your viewmodel like this:
public bool IsMessageMenuEnabled => !this.IsChecked;
public bool IsChecked
{
get => this.isChecked;
set
{
this.isChecked = value;
this.OnPropertyChanged();
this.OnPropertyChanged(nameof(this.IsMessageMenuEnabled));
}
}
I have a CheckBox that's set up like so:
<CheckBox x:Name="ViewTypeCheckbox" IsChecked="{Binding ViewType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding Refresh}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
This functions as it's supposed to. When checked or unchecked by mouse click, the command is fired in the ViewModel.
You see the checkBox is databound to a bool property ("ViewType") that regularly turns from true to false and viseversa in response to user input.
The problem is I need the EventTrigger to fire when checked or unchecked by the ViewModel.
I've tried changing the "EventName" to "Checked", "IsChecked" and "UnChecked" but that doesn't seem to do anything.
Is there any additional code I need to implement? How would I get this to work?
You don't need Interaction.Triggers,
WPF provides support for commands out of the box.
Try simplifying your XAML by using a command attribute instead. It should resolve your issue.
If you need to call some code when the ViewTypeCheckbox.IsChecked changes its value, you can simply register an event handler to the PropertyChanged event of your view model (assuming it implements INotifyPropertyChanged), then call the code when the property ViewType changes:
myViewModel.PropertyChanged += new PropertyChangedEventHandler(onPropertyChanged);
...
private void onPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName=="ViewType")
{
// Do your stuff here
// Ex. fire the Refresh Command
}
}
This can be done in the ViewModel class itself or whatever you need.
To complete the example I add a short implementation of INotifyPropertyChanged in the viewmodel class:
public class MyViewModel : INotifyPropertyChanged
{
...
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler!=null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
...
// property definition to bind to ViewTypeCheckbox.IsChecked
private bool _viewType;
public bool ViewType
{
get { return _viewType; }
set
{
if (value != _viewType)
{
_viewType = value;
RaisePropertyChanged("ViewType");
}
}
}
}
Hope it helps
You don't need a trigger to execute your action. You can do it in the viewmodel when the property change.
public Boolean ViewType
{
get
{
return this.something;
}
set
{
this.something = value;
if (true == this.something)
{
this.Refresh();
}
}
}
I am trying to enable and disable a button in a WPF (PRISM) user control based on data entered by the user.
In the constructor I do
SubmitCommand = new DelegateCommand<object>(OnSubmit, CanSubmit);
public ICommand SubmitCommand { get; private set; }
private void OnSubmit(object arg)
{
_logger.Log(arg.ToString());
}
private bool CanSubmit(object arg)
{
return Title.Length > 0;
}
private string _title="";
public string Title
{
get { return _title; }
set
{
if (_title != value)
{
_title = value;
this.RaisePropertyChanged();
}
}
}
I bound the SubmitCommand in the Xaml as below
<Button Content="Submit" Width="100" Command="{Binding Path=SubmitCommand}" CommandParameter="{Binding ElementName=TitleText, Path=Text}" />
The issue is when title value changes, the button does not get enabled. May be I am missing something. Thanks for your help!
It sounds like you're needing to raise the CanExecuteChanged event on your command. For more details, see http://wpftutorial.net/DelegateCommand.html and http://msdn.microsoft.com/en-us/library/system.windows.input.icommand.canexecutechanged.aspx
Note that the first link is to an implementation of DelegateCommand, and is probably not what you're actually using. For the prism DelegateCommand, you simply need to call the RaiseCanExecuteChanged() method when you want to determine whether the button should be reenabled.
Good luck!
Nate
Add:
SubmitCommand.RaiseCanExecuteChanged();
After:
this.RaisePropertyChanged();
I am relatively new to WPF, XAML and Data-bindings. I have a view (Window) and a view-model.
I have tried to implement the MVVM pattern which means neither the view nor the view-model hold a reference to each other. All data exchange happens via data-bindings.
So far so good but now I have run into a problem I can't find a solution for.
On my view I have a button Start which is bound to a command.
<Button Command="{Binding NextCommand}" Content="Next">
NextCommand is of type ActionCommand : ICommand
In my case NextCommand simply calls a private method within the view-model.
The problem I can not find a solution so far is the following:
How to close the window at the end of the view-models NextCommandAction method?
private void NextCommandAction(object o)
{
...
...
// close the window
}
Since I do not have a reference to the view I can not just set DialogResult = true;
The only working solution I have found so far is to add a hidden radio-button to the view and bind it's value to a property CloseView and create a method CloseView within the xaml.cs file which is bound to the Checked event of the hidden radio-button. Within that method I set DialogResult = true;
Although this works I feel like there has to be a better solution than adding hidden elements to your view!
You can pass the window reference as CommandParameter to the Close command and do whatever required on the window.
<Button Content="Close" Command="{Binding Path=CloseCommand}"
CommandParameter="{Binding ElementName=Window}"/>
private void CloseCommand(object sender)
{
Window wnd = sender as Window;
wnd.Close();
}
CommandParameter="{Binding ElementName=Window}" assumes that you have an element in your XAML named "Window". e.g, your Window tag would need Name="Window"
This question was one of the first things that came up when I googled to check if DialogResult is a dependency property (it isn't :-) )
Add a dependency property to your Window:
public static readonly DependencyProperty InteractionResultProperty =
DependencyProperty.Register(
nameof(InteractionResult),
typeof(Boolean?),
typeof(MyWpfWindow1),
new FrameworkPropertyMetadata(default(Boolean?),
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
OnInteractionResultChanged));
public Boolean? InteractionResult
{
get => (Boolean?) GetValue(InteractionResultProperty);
set => SetValue(InteractionResultProperty, value);
}
private static void OnInteractionResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((MyWpfWindow1) d).DialogResult = e.NewValue as Boolean?;
}
I named my property InteractionResult though a good name would have also worked.
In the xaml right after the
you can bind it with a style
<Window.Style>
<Style TargetType="{x:Type z:MyWpfWindow1}">
<Setter Property="InteractionResult"
Value="{Binding UpdateResult}" />
</Style>
</Window.Style>
UpdateResult is the property in my viewmodel.
private Boolean? _updateResult;
public Boolean? UpdateResult
{
get => _updateResult;
set => SetValue(ref _updateResult, value);
}
The SetValue method is the usual notify property
protected virtual Boolean SetValue<T>(ref T field, T value,
[CallerMemberName]String propertyName = null)
{
if (Equals(field, value))
return false;
field = value;
RaisePropertyChanged(propertyName);
return true;
}
and the property gets set in the usual way
<Button Content="Cancel"
Command="{Binding CancelCommand}" />
ICommand CancelCommand { get; }
private void OnCancel()
{
UpdateResult = false;
}
Disclaimer: works on my computer.
Inspired by Chandrashekhar Joshi's answer
(but not using the elements's name):
Define CommandParameter in Button:
<Button
Command="{Binding CloseCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"
Content="Close" />
Define Command (and Implementation):
CloseCommand = new DelegateCommand<Window>((w) => w.DialogResult = true);
i have an XamDataPresenter (XamDataGrid) bound to a collection in the ViewModel:
XAML:
<igDP:XamDataPresenter x:Name="dataPresenter" DataSource="{Binding Path=AppServers, UpdateSourceTrigger=PropertyChanged}" IsSynchronizedWithCurrentItem="True">
</igDP:XamDataPresenter>
Code:
public ShellViewModel()
{
AppServers = new BindingListCollectionView(new BindingList<AppServer>(_context.GetAllAppServers()));
AppServers.CurrentChanged += new EventHandler(AppServers_CurrentChanged);
}
void AppServers_CurrentChanged(object sender, EventArgs e)
{
NotifyOfPropertyChange(() => CanSaveAppServers);
NotifyOfPropertyChange(() => CanDeleteAppServers);
}
The CanSaveAppServers property:
public bool CanSaveAppServers
{
get
{
return (_appServers.SourceCollection as BindingList<AppServer>).Any(x => x.ChangeTracker.State != ObjectState.Unchanged);
}
}
The CanSaveAppServers property should be false if an item of the collection is changed. But how is the CanSaveAppServers called? Another event? Or the wrong collection type? Shouldn't this be done automatically in some way?
Thanks in advance.
If you are letting Caliburn bind via naming conventions, then you have a public method named SaveAppServers. Caliburn creates an ICommand that is bound to the Button so that when the button is clicked, ICommand's Execute() is called. In the meantime, there is a CanExecute() method on ICommand that is used to determine whether the button is enabled or not.
When you call NotifyOfPropertyChange(() => CanSaveAppServers), this ends up making the ICommand raise its CanExecuteChanged event, which makes WPF refresh by calling CanExecute() again, which under the covers is getting CanSaveAppServers.