I have a simple button:
<Button Content="Print" Command="{Binding PrintCommand}"/>
...with a command:
private RelayCommand _printCommand;
public ICommand PrintCommand
{
get
{
if (_printCommand == null)
{
_printCommand = new RelayCommand(param => Print(),
() => (Files != null && Files.Count > 0));
}
return _printCommand;
}
}
It is enabled only when the Files
collection is either not null or has some items in it. Here's the collection:
private ObservableCollection<RecordModel> _files;
public ObservableCollection<RecordModel> Files
{
get { return _files; }
set
{
if (_files == value)
{
return;
}
_files = value;
OnPropertyChanged("Files");
}
}
The collection is bound to a ListView
in the window. Thus far, nothing special... and here's where the odd behavior comes in...
If I have enough items in the collection to have ListView
's ScrollBar
to show, then my button is shown as Enabled
, which is good. If I have no items, then it's Disabled
, which is also good. However, if I have just enough items to fill a portion of the visible ListView
, without triggering the appearance of the ScrollBar
, then my button shows as Disabled
. If I focus on any control, including the button itself, then it pops-up as Enabled
. I've no idea what's going on. At first, I thought it might have been a button template I was using, so I got rid of it and kept the button with the default setup, yet the odd behavior remained.
Any ideas what's going on?
Here's the RelayCommand
class. I'm not sure if a problem could be within it, but that's what I've been using for a while:
public class RelayCommand : ICommand
{
readonly Action<object> _execute;
readonly Func<bool> _canExecute;
public RelayCommand(Action<object> execute) : this(execute, null) { }
public RelayCommand(Action<object> execute, Func<bool> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute();
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
EDIT:
Here's how I populate my collection.
public FileManagerViewModel()
{
LoadCollection();
}
private void LoadCollection()
{
Task task = new Task(() =>
{
Files = DbWorker.GetFiles();
});
task.Start();
}
Here's how I bind the collection to the ListView
:
<Window.DataContext>
<vm:FileManagerViewModel/>
</Window.DataContext>
<Window.Resources>
<CollectionViewSource Source="{Binding Files}" x:Key="GroupedFiles">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="RepNum"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
<ListView ItemsSource="{Binding Source={StaticResource GroupedFiles}}">
...
</ListView
EDIT:
Hmm, I don't know if this is it or how it could be causing it (especially with the whole ScrollBar
situation), but when I don't use the Task
to update my collection, I don't experience this behavior. Of course, I then have to deal with hanging due to a lengthy operation. Not sure how I can remedy this, considering I don't want to block the UI thread. I even tried this and it didn't change anything:
var temp = new ObservableCollection<RecordModel>();
Task task = new Task(() =>
{
temp = DbWorker.GetFiles();
});
task.ContinueWith((result) =>
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new Action(() =>
{
Files = temp;
}));
});
task.Start();
But I don't see an issue with properties not being updated. I've checked and all the properties update as needed. It's just something with that little hang in the status update of CanExecute
that only updates by focus change (in this scenario).
Just based on what I know, it seems as if there's an issue between threads and Commands... hmm. Every time I manually give UI element a focus by clicking on, Commands update (or so it appears). This also happens if ScrollBar appears or dissapears. But then other UI elements don't do anything, such as text.