so I am trying to use the CheckBox Control with MVVM logic. However the only event existing is CheckedChanged, which also triggers if I am navigating from the page for example.
I am searching for a Clicked event, like a button has.
Do I need to create a custom control with custom renderer, or is there a better solution?
Looking forward to replies.
[EDIT]
To provide more information about my issue, I will put code examples below.
My CheckBoxes are inside a ListView. Each CheckBox is defined like this in XAML:
<CheckBox
IsChecked="{Binding IsCompleted}">
<CheckBox.Behaviors>
<prism:EventToCommandBehavior
EventName="CheckedChanged"
Command="{Binding SubTaskStateChangedCommand}"/>
</CheckBox.Behaviors>
</CheckBox>
The ItemSource of the ListView has a property IsCompleted and a DelegateCommand SubTaskStateChangedCommand. It is worth mentioning that i am using Prism.
In the constructor:
SubTaskStateChangedCommand = new DelegateCommand(OnSubTaskStateChangedCommandExecuted);
Class SubTaskModel:
public DelegateCommand SubTaskStateChangedCommand { get; set; }
private void OnSubTaskStateChangedCommandExecuted()
{
//Do something
}
private bool _isCompleted;
public bool IsCompleted
{
get { return _isCompleted; }
set { _isCompleted = value; OnPropertyChanged(); }
}
So when I am navigating to another page in my ViewModel using the Prism NavigationService, the OnSubTaskStateChangedCommandExecuted Method gets triggered. However, I noticed that when this happens, the IsCompleted value DOES NOT change.
Related
I created a new WPF MVVM application via Online Templates->WPF in VS2010->WPF MVVM project template. I created a checkbox labeled "Refresh Enabled?" next to the "Refresh" button that I wanted to enable/disable the "Refresh" button when clicked. I bound the IsChecked property of my checkbox to aMainWindowViewModel property I called CanRefreshDate, and it raises RaisePropertyChanged(()=>CanRefreshDate); in its setter. Also in the MainWindowViewModel, I added my newly created CanExecuteRefreshDate(), which returns the bool of CanRefreshDate property. However, when I click the checkbox, the button "Refresh" is never enabled/disabled to match. What is the proper way to fix this, and is this an oversight in the template or what?
Here's my modifications to the template code:
Xaml:
<CheckBox Content="Refresh Enabled?"
IsChecked="{Binding CanRefreshDate}"/>
MainWindowViewModel.cs:
private bool _CanRefreshDate;
public bool CanRefreshDate
{
get { return _CanRefreshDate; }
set
{
if (_CanRefreshDate != value)
{
_CanRefreshDate = value;
RaisePropertyChanged(() => CanRefreshDate);
}
}
}
public ICommand RefreshDateCommand { get { return new DelegateCommand(OnRefreshDate, CanExecuteRefreshDate); } }
private bool CanExecuteRefreshDate()
{
return CanRefreshDate;
}
I noticed that the template had RaiseCanExecuteChanged() misspelled RasieCanExecuteChanged() in DelegateCommand.cs and changed that. I was able to get it all working by removing RaiseCanExecuteChanged() and modifying the
public event Handler CanExecuteChanged;
to :
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
However, I would like to know what the proper solution for this is and why the template doesn`t work. Am i missing something, doing something wrong or what? Please create a new solution and use the template I did and tell me what is going on! Thanks!
The author fixed the issue and released version 4.1 of the template yesterday.
I would like on navigation between views in a WPF application using Prism to have the ability to set focus to sepecific textboxes so a user can perform navigation and then begin typing in the relevant textbox without a second click into the textbox.
I have an application built with Prism that has a Shell with a ContentControl "MainContentRegionContentControl". I then have some buttons across the top when on clicking them I do a region.RequestNavigate("UserControlToLoad"). On the UserControl I have the OnNavigatedTo and in that method I call this.MainTextBox.Focus().
The above doesn't appear to work, the navigation appears to work and the OnNavigatedTo method is called, but the textbox doesn't have focus.
I've added FocusManager.IsFocusScope="True" to the textbox, but this hasn't made a difference.
Use Loaded() method for each page instead of OnNavigatedTo() and TextBox.Focus() will work fine then ;)
Try the following... In your View implement IActiveAware
class ViewModel : IActiveAware
{
#region IActiveAware Members
private bool isActive = false;
public bool IsActive
{
get
{
return isActive;
}
set
{
if (value != isActive)
{
isActive = value;
OnIsActiveChanged(EventArgs.Empty);
}
}
}
public event EventHandler IsActiveChanged = delegate { };
protected virtual void OnIsActiveChanged(EventArgs args)
{
IsActiveChanged(this, args);
}
#endregion
}
OnIsActiveChanged, try setting focus to the TextBox you'd like to focus when IsActive becomes true
I have three xaml pages and related ViewModels: main.xaml, MainViewModel.cs; page1.xaml, Page1ViewModel.cs; page2.xaml, page2ViewModel.cs. There is a TabControl in main.xaml.
I want to load and show the page1.xaml in TabItem when the application initializing, and page1.xaml will be changed to page2.xaml when clicking the button included in page1.xaml; page2.xaml will be changed to page1.xaml when clicking the button included in page2.xaml.
All the events or commands need to be implemented in ViewModels. My Questions:
How to load the pages to the TabItem?
How to change the page in the TabItem?
Above questions have been solved by Rachel, Thanks.
I want show page1 and page2 in TabItem1, page1 will disappear and page2 will show when clicking the button which included in page1.
Thanks.
Your MainPageViewModel should hold a collection of what pages are in the TabControl, and the SelectedPage. It should also contain an ICommand which will change the current page.
For example,
// These should be full properties that raise PropertyChange notifications
public ObservableCollection<IPageViewModel> Tabs { get; set; }
public int SelectedTabIndex { get; set; }
private ICommand ChangeTabIndexCommand { get; set; }
MainPageViewModel()
{
Tabs = new ObservableCollection<IPageViewModel>();
Tabs.Add(new Page1ViewModel());
Tabs.Add(new Page2VieWModel());
SelectedTab = 0;
ChangeTabIndexCommand = new RelayCommand<int>(ChangeTab);
}
void ChangeTab(int newIndex)
{
if (newIndex >= 0 && newIndex < Tabs.Count())
SelectedTab = newIndex;
}
Your MainView would look like this:
<TabControl ItemsSource="{Binding Tabs}" SelectedIndex="{Binding SelectedIndex}" />
If you are using Silverlight 5, I believe you can use implicit DataTemplates, however if not you'll have to use something like a DataTemplateSelector or a Converter to tell Silverlight how to draw each ViewModel. I usually use Microsoft PRISM's DataTemplateSelector
There are a number of ways to hook up the ChangeTabIndexCommand. My preference is to use some kind of Messaging System, however you could also hook up the event in the Constructor of the MainViewModel.
I have a requirement for which i need a MultiState Checkboxes in WPF...
Also as i am using MVVM so handling binding and Commands should follow the same as i will use it in my Views.
I have seen a Multistate checkbox in DotnetNuke(made in ASP.NET) but how to make it in WPF
some inputs in this regards will be helpful
Some example will be great...
Checkboxes have specific functionality (checked, unchecked, and optionally indeterminate).
Based on your comment, I would think it would be easiest to just do it as a button. I don't have time now to test out an actual example, but here some pseudocode to get you going:
XAML
<Button Command="{Binding ToggleDecisionState}">
<Button.Content>
<Image Source="{Binding CurrentDecisionIcon}" />
<Button.Content>
</Button>
ViewModel (leaving out MVVM implementation details)
enum Decisions
{
Agree,
Disagree,
Maybe,
DoNotKnow
};
public Decisions CurrentDecision
{
get {}
set {}
}
public RelayCommand ToggleDecisionStateCommand
{
// In here, call code to execute toggle
if (mCurrentDecision == Decisions.DoNotKnow)
CurrentDecision = Decisions.Agree;
else
CurrentDecision += 1;
}
public ImageSource CurrentDecisionIcon
{
get
{
ImageSource img = [some default image];
switch (mCurrentDecision)
{
case Decisions.Agree:
img = [path to Agree icon];
break;
// Other cases here
}
return img;
}
}
if you want to use 3-state check box, you must change the behind boolean value(in ViewModel)
to bool? type.
public bool? IsEnabled { get; set; }
and Set this property for CheckBox
IsThreeState = True;
I have a list of ToggleButtons being used as the ItemTemplate in a ListBox similar to this answer using the MultiSelect mode of the Listbox. However I need to make sure at least one item is always selected.
I can get the proper behavior from the ListBox by just adding an item back into the ListBox's SelectedItems collection on the ListBox.SelectionChanged event but my ToggleButton still moves out of its toggled state so I think I need to stop it earlier in the process.
I would like to do it without setting IsEnabled="False" on the last button Selected because I'd prefer to stay with the Enabled visual style without having to redo my button templates. Any ideas?
You can override the OnToggle method to prevent toggling the state, by not calling the base implementation :
public class LockableToggleButton : ToggleButton
{
protected override void OnToggle()
{
if (!LockToggle)
{
base.OnToggle();
}
}
public bool LockToggle
{
get { return (bool)GetValue(LockToggleProperty); }
set { SetValue(LockToggleProperty, value); }
}
// Using a DependencyProperty as the backing store for LockToggle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty LockToggleProperty =
DependencyProperty.Register("LockToggle", typeof(bool), typeof(LockableToggleButton), new UIPropertyMetadata(false));
}
Have you tried using RadioButtons instead? It normally can't be deselected without selecting another one. It can also be styled to look like a ToggleButton:
<RadioButton Style="{StaticResource {x:Type ToggleButton}}"/>
Or, if you already have a Style for it, just make it BasedOn="{x:Type ToggleButton}". Note that the Visual Studio Editor shows an error in the first case, but it compiles and works fine.
This is hackey, but if you don't want custom code you could always use the property "IsHitTestVisible", when you don't want them to uncheck it, simply set IsHitTestVisible equal to false. However, they may be able to tab to the control and toggle it using the space bar.
Thomas's answer works fine, but you don't even need the extra dependency property. Your button will update correctly if you have the class inherit from ToggleButton so you can override the OnToggle method, and you change the IsChecked bound property on the ViewModel.
Xaml:
<myControls:OneWayFromSourceToTargetToggle x:Name="MyCustomToggleButton"
Command="{Binding Path=ToggleDoStuffCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self}}"
IsChecked="{Binding Path=ToggleIsCheckedConditionVar,
Mode=OneWay}"
/>
Added ToggleButton Class:
public class OneWayFromSourceToTargetToggle : ToggleButton
{
/// <summary>
/// Overrides the OnToggle method, so it does not set the IsChecked Property automatically
/// </summary>
protected override void OnToggle()
{
// do nothing
}
}
Then in the ViewModel just set bool ToggleIsCheckedCondition to true or false. This is a nice way to do it because you are following good MVVM practices.
ViewModel:
public bool ToggleIsCheckedCondition
{
get { return _toggleIsCheckedCondition; }
set
{
if (_toggleIsCheckedCondition != value)
{
_toggleIsCheckedCondition = value;
NotifyPropertyChanged("ToggleIsCheckedCondition");
}
}
}
public ICommand ToggleDoStuffCommand
{
get {
return _toggleDoStuffCommand ??
(_toggleDoStuffCommand = new RelayCommand(ExecuteToggleDoStuffCommand));
}
}
private void ExecuteToggleDoStuffCommand(object param)
{
var btn = param as ToggleButton;
if (btn?.IsChecked == null)
{
return;
}
// has not been updated yet at this point
ToggleIsCheckedCondition = btn.IsChecked == false;
// do stuff
}
}
Adding a little bit to #Joachim-Mairböck's great answer in case you want to do the same programmatically:
new RadioButton {
...
GroupName = "myButtonGroup"
Style = Application.Current.TryFindResource(typeof(ToggleButton)) as Style
...
}