How to disable a button if no items are selected in a ListView
Solution 1
There are a few things wrong here.
Precedence, if you set
IsEnabled
on the control itself the style will never be able to change it.ElementName, it's an
ElementName
, not a path, just one string that gives the name of one element. Everything beyond that goes into the Path.Style syntax, if you set a
Style.TargetType
you should not set theSetter.Property
with a type prefix (although leaving it does not break the setter).
By the way, this alone is enough:
<Button IsEnabled="{Binding SelectedItems.Count, ElementName=lv}" ...
Solution 2
It's obvious that you aren't using Commanding (ICommand Interface
). You should either use that (and preferably the Model-View-ViewModel architecture).
But, if you want to stick with code-behind and XAML:
<ListView SelectionChanged="AccountListView_SelectionChanged" ... />
private void AccountListView_SelectionChanged(Object sender, SelectionChangedEventArgs args)
{
DebitButton.IsEnabled = (sender != null);
//etc ...
}
More information on MVVM: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
You need to set the DataContext of the View (UserControl) to the instance of the ViewModel you want to use. Then, from there, you can bind to properties on the ViewModel, including ICommand
s. You can either use RelayCommand
(see link above) or use Commanding provided by a framework (for example, Prism provides a DelegateCommand
). These commands take an Action (Execute) and a Func (CanExecute). Simply provide the logic in your CanExecute. Of course, you'd also have to have your ListView SelectedItem (or SelectedValue) be databound to a property on your ViewModel so you can check to see if it's null within your CanExecute function.
Assuming you use RelayCommand
you don't have to explicitly call the RaiseCanExecuteChanged
of an ICommand
.
public class MyViewModel : ViewModelBase //Implements INotifyPropertyChanged
{
public MyViewModel()
{
DoSomethingCommand = new RelayCommand(DoSomething, CanDoSomething);
}
public ObservableCollection<Object> MyItems { get; set; }
public Object SelectedItem { get; set; }
public RelayCommand DoSomethingCommand { get; set; }
public void DoSomething() { }
public Boolean CanDoSomething() { return (SelectedItem != null); }
}
<ListView ItemsSource="{Binding MyItems}" SelectedItem="{Binding SelectedItem}" ... />
<Button Command="{Binding DoSomethingCommand}" ... />
Jonathan
Updated on June 05, 2022Comments
-
Jonathan almost 2 years
I have a
ListView
Contained in a UserControl I would like to disabled a button when no items are selected in the UserControl, would it be the right way to do it? So far, it doesn't disable, it just stays enable all the way. I've included the xaml code.searchAccountUserControl is the UserControl name property in the xaml. And AccountListView is the
ListView
name property in the userControl xaml.<Button Content="Debit" IsEnabled="true" HorizontalAlignment="Left" Margin="18,175,0,0" Name="DebitButton" Width="128" Grid.Column="1" Height="32" VerticalAlignment="Top" Click="DebitButton_Click"> <Button.Style> <Style TargetType="Button"> <Style.Triggers> <DataTrigger Binding="{Binding ElementName=searchAccountUserControl.AccountListView, Path=SelectedValue}" Value="{x:Null}" > <Setter Property="Button.IsEnabled" Value="false"/> </DataTrigger> </Style.Triggers> </Style> </Button.Style> </Button>
Thanks.
Finally i've used :
in my ViewModel :
private bool _isSelected; public bool IsSelected { get { return _isSelected; } set { _isSelected = _account.View.CurrentItem != null; PropertyChanged.SetPropertyAndRaiseEvent(this, ref _isSelected, value, ReflectionUtility.GetPropertyName(() => IsSelected)); } }
And then Use isEnabled = "{Binding Path=IsSelected}" in the xaml.
-
myermian over 12 yearsgood points... I completely ignored his xaml-only approach and went with a MVVM lecture + XAML/Code-Behind mix (he's using this mix already).
-
Jonathan over 12 yearsI am actually using a Model View ViewModel architecture. I just didnt know how to do it so and searched on the internet for a clue.
-
Jonathan over 12 yearsMy Xaml uses a baseWindowViewModel And i'm also using Binding Path. But as said i didnt know how to do it with the Binding so i tried to find a way with the code Behind, Altought i would much rather keep it straight with my ViewModel approach.
-
myermian over 12 yearsWhat framework are you using (if any)? And using events is not MVVM ... binding (including command binding) is MVVM.
-
Jonathan over 12 yearsSo i guess i could use <Button IsEnabled="{Binding CollectionView.View.CurrentItem}"> and make a converter?
-
H.B. over 12 years@Jonathan: A trigger would work too if you watch precedence and fix the binding, but if you can bind directly to the ListView you can do the binding as shown above which will result in a conversion of the count to bool: 0 selected -> false = disabled; 1 or more selected -> true = enabled.
-
Jonathan over 12 yearsYes i know i'm talking about other parts of the code. With A viewModel and {Binding Path=... Converter ect...}
-
Jonathan over 12 years@Hb : Since the listView is in the userControl, i dont know if i can bind it directly, I dont know what would be the best approach as i said, to stay with the pattern and keep the code clean. Can i do something like <Button IsEnabled="{Binding Usercontrol.ListView.SelectedItems.Count, ElementName=lv}"
-
myermian over 12 years@Jonathan: The reason I assumed you weren't using MVVM is because you have named XAML controls (unnecessary) and you have a Click event on your button (unnecessary).
-
H.B. over 12 yearsThat was an example, in your case you probably want the ElementName to point to the UserControl, you can expose the ListView with a public get-only property on the UserControl then you can bind to it, or you ceate a readonly bindable property which internally binds to the count, then you expose less of your UserControl.
-
Jonathan over 12 yearsOk, yes we are, all our viewModels implements INotifyPropertyChanged I guess we are just not using the RelayCommands.
-
myermian over 12 years@Jonathan: I realize you state you are using MVVM. I said I assumed you weren't because your sample code had conventions that go against MVVM, for exmaple: Naming your XAML controls and using the Click event instead of Command Binding.
-
Jonathan over 12 yearsYeah, sorry :) We are not fully using it. Yet.
-
myermian over 12 years@Jonathan: Well I hope that my samples and links help you get on the right track. Seriously look at using existing frameworks because they come with samples, documentation, and a lot of great code. Personally I use Prism, but that might be a bit advanced to start with.
-
Jonathan over 12 yearsFinally i've added in my ViewModel : private bool _isSelected; public bool IsSelected { get { return _isSelected; } set { _isSelected = _account.View.CurrentItem != null; PropertyChanged.SetPropertyAndRaiseEvent(this, ref _isSelected, value, ReflectionUtility.GetPropertyName(() => IsSelected)); } } And then Use isEnabled = "{Binding Path=IsSelected}"
-
Jonathan over 12 yearsFinally i've added in my ViewModel : private bool _isSelected; public bool IsSelected { get { return _isSelected; } set { _isSelected = _account.View.CurrentItem != null; PropertyChanged.SetPropertyAndRaiseEvent(this, ref _isSelected, value, ReflectionUtility.GetPropertyName(() => IsSelected)); } } And then Use isEnabled = "{Binding Path=IsSelected}" And i will look toward Prism. Thanks.
-
Jonathan over 12 yearsWe are also using NHibernate and sessions so i don't know if it can become an issue with full MMVM
-
cd491415 over 5 yearsElementName does not exist in Xamarin.forms. This works only in WPF I believe