Create a new ICommand object in the ViewModel - wpf

Both ICommand objects are bound to a ViewModel.
The first approach seems to be used often.
But the second one saves some lines of code but would it not create everytime a new ICommand object when the Binding is refreshed so its a waste of resources?!
private LightCommand _deleteDocumentCommand;
public LightCommand DeleteDocumentCommand
{
get { return _deleteDocumentCommand ?? (_deleteDocumentCommand = new LightCommand(() => DeleteDocument(), () => CanDeleteDocument)); }
}
public LightCommand DeleteDocumentCommand
{
get { return new LightCommand(() => DeleteDocument(), () => CanDeleteDocument); }
}

Yes your 2nd method creates a new command every time the command is referenced, but I also find your 1st method rather hard to read.
My preferred way to make a command in the ViewModel is
private LightCommand _deleteDocumentCommand;
public LightCommand DeleteDocumentCommand
{
get
{
if (_deleteDocumentCommand == null)
{
_deleteDocumentCommand = new LightCommand(
() => DeleteDocument(), () => CanDeleteDocument);
}
return _deleteDocumentCommand;
}
}
It might be more lines of code, but it is easy to read and understand. Besides, usually all my public Properties/Commands are generated by macros and dumped into a #region Properties area that stays collapsed the entire time I work with the ViewModel, so I don't have to scroll through pages of get/set methods.

yes it would. You are better off instantiating it once, so that you have something like this:
LightCommand DeleteCommand { get; set;}
and then in our VM instantiation you assign to it. Or you could use your first example.

I assume you're looking for verification, and that's correct:
Everytime the Binding is refreshed, (or the command is called), a new object is instantiated. It looks like a clear waste of resources.

Related

AutoRefreshOnObservable only works once. Why?

I'm working on a small programm where i'm evaluating if reactive ui is the right framework for another project. So far so good... At the moment i'm a little bit lost in a DynamicData related function. I'm trying to execute a command in the MainViewWindow every time a combo box in a ReactiveUserControl is changed. All my Models are extending ReactiveObject and the Properties are set up with the RaiseAndSetIfChanged setter.
In my ReactiveUserControl ViewModel I invoke my Command SaveImage from the ReactiveUserControl ViewModel as it is described here:
https://reactiveui.net/docs/handbook/message-bus/#ways-to-avoid-using-messagebus
Defining the ObservableCollection
public ObservableCollection<FileViewModel> VisibleFiles { get; protected set; }
Initialize the Collection, Files is a SourceList
WatchFiles = ReactiveCommand.Create(() =>
{
VisibleFiles = new ObservableCollection<FilesViewModel>(Files.Items);
VisibleFiles.ToObservableChangeSet().AutoRefreshOnObservable(doc => doc.SaveImage).Select(_ => WhenAnyFileChanged()).Switch().Subscribe<FilesViewModel>(x => {
Console.WriteLine("HOORAY");
});
});
private IObservable<FilesViewModel> WhenAnyFileChanged()
{
return VisibleFiles.Select(x => x.SaveFile.Select(_ => x )).Merge();
}
The First time a combo box changed it gets evaluated correct. I get the "Hooray". But every time after that there is no output. If I invoke the Watch Files Command again it is again working once.
Why is this happening, and how can i solve it to print every time a file changed the "Hooray" ? I can see, that the ObservableCollection detects the change, and also the Command in the ReactiveUserControl is invoked on the change. But the WhenAnyFileChanged Method doesn't return the changed element after the first invokation.
Hopefully it is understandable what I'm trying to achieve, an what's the problem.
Update: I don't know why, but if i check the ChangeSet in the Select() i get TotalChanges 10 at initialisation, which is right. Then with my first working change TotalChanges is 0 but is evaluated right. On my next attempt on changing i still get 0 TotalChanges but also no correct evaluation in WhenAnyFileChanged().
Refreshes() is 1 on every change.
Update 2: Changing AutoRefreshOnObservable() to AutoRefresh() brings the desired functionality.
I copied the original message bus example and wrote a unit test to see whether the code behaves as expected. I can confirm the issue you are seeing is present in the example. The following code only fires once.
public MainViewModel()
{
OpenDocuments = new ObservableCollection<DocumentViewModel>();
OpenDocuments
.ToObservableChangeSet()
.AutoRefreshOnObservable(document => document.Close)
.Select(_ => WhenAnyDocumentClosed())
.Switch()
.Subscribe(x => OpenDocuments.Remove(x), ex=>{},()=>{});
}
IObservable<DocumentViewModel> WhenAnyDocumentClosed()
{
return OpenDocuments
.Select(x => x.Close.Select(_ => x))
.Merge();
}
And here's the test to prove it. It fails on the second attempt to remove.
[Fact]
public void MyTest()
{
//I added an id field to help with diagnostics / testing
_mainViewModel.OpenDocuments.Count.Should().Be(4);
_mainViewModel.OpenDocuments.Any(dvm => dvm.Id == "1").Should().BeTrue();
_mainViewModel.OpenDocuments[0].Close.Execute().Subscribe();
_mainViewModel.OpenDocuments.Count.Should().Be(3);
_mainViewModel.OpenDocuments.Any(dvm => dvm.Id == "1").Should().BeFalse();
_mainViewModel.OpenDocuments[0].Close.Execute().Subscribe();
_mainViewModel.OpenDocuments.Count.Should().Be(2);
_mainViewModel.OpenDocuments.Any(dvm => dvm.Id == "2").Should().BeFalse();
}
I am unsure why this fails, but the most optimal fix is to make use of Dynamic Data's MergeMany operator which is similar to Rx's Merge but automatically wires observables when items are added to the underlying list and unwires them when items are removed. The fix is:
public class MainViewModel : ReactiveObject
{
public ObservableCollection<DocumentViewModel> OpenDocuments { get;}
public MainViewModel()
{
OpenDocuments = new ObservableCollection<DocumentViewModel>();
OpenDocuments
.ToObservableChangeSet()
.MergeMany(x => x.Close.Select(_ => x))
.Subscribe(x => OpenDocuments.Remove(x));
}
}
Running the same unit tests pass.
The code with unit test is available in this gist

MVVM RelayCommand CanExecute

I'm implementing an RelayCommand with an execute and an canExecute part. The RelayCommand works when it is without the canExecute part, however when I add the canExecute part, the command locks the button. The RelayCommand only checks whether or not the button can be executed as long as the CanExecute part is true. Once the canExecute part becomes false, the button can no longer be clicked, even if it is supposed to. How do I make sure that every time I click on the button it controls whether or not it can be executed, and doesn't lock it forever, once it cannot be executed?
RedoCommand = new RelayCommand(undoRedoController.Redo,undoRedoController.CanRedo);
public bool CanRedo()
{
redoStack.Count();
redoStack.Any();
return redoStack.Any();
}
public void Redo()
{
if (redoStack.Count() <= 0) throw new InvalidOperationException();
IUndoRedoCommand command = redoStack.Pop();
undoStack.Push(command);
command.Execute();
}
public class UndoRedoController
{
private static UndoRedoController controller = new UndoRedoController();
private readonly Stack<IUndoRedoCommand> undoStack = new Stack<IUndoRedoCommand>();
private readonly Stack<IUndoRedoCommand> redoStack = new Stack<IUndoRedoCommand>();
private UndoRedoController() { }
public static UndoRedoController GetInstance() { return controller; }
There has been a hiatus with MVVMLight due to the fact that after the .NET 4.5 update the CommandManager no longer fires the can execute check. This has since been solved. Instead of including the GalaSoft.MvvmLight.Command namespace you should use the GalaSoft.MvvmLight.CommandWpf namespace. The RelayCommand defined in that namespace is still checking the CanExecute function that you pass to the command.
Took me about a day to find out what the hell was going wrong in my application. I hope this will help some of you.
Here is a blog post by the developer explanining why this is necessary.
For some reason you have to do the following:
public RelayCommand RedoCommand{
get;
set;
}
you can also put private before set optional, depending on your access level. Then you do
RedoCommand = new RelayCommand(() => undoRedoController.Redo(), () => undoRedoController.CanRedo());
Now your able to call RedoCommand.RaiseCanExecuteChanged();
And everything works.
If you are using an unpatched .net 4.5. Microsoft broke the .CanExecute event.
http://connect.microsoft.com/VisualStudio/feedback/details/753666/net-4-0-application-commands-canexecute-not-updating-in-4-5
If you are using the RelayCommand from http://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090030 and are not raising the CanExecuteChanged event when redoStack changes.
(Answering from a Silverlight perspective so assuming this will help you.)
Are you doing a RedoCommand.RaiseCanExecuteChanged() anywhere? Once whatever condition you are monitoring changes, you'll need to raise this command manually.
EDIT
Since you are using MVVM Light.. Heres sample code:
RedoCommand = new RelayCommand(undoRedoController.Redo,undoRedoController.CanRedo);
public bool CanRedo()
{
redoStack.Count();
redoStack.Any();
return redoStack.Any();
}
public void Redo()
{
if (redoStack.Count() <= 0) throw new InvalidOperationException();
IUndoRedoCommand command = redoStack.Pop();
undoStack.Push(command);
command.Execute();
// At this point, your stacks have changed; that is, the stacks
// may or may not contain items. Thus, raise the commands CanExecute part
// which will in turn enable/disable the commands based on the functions
// return value
RedoCommand.RaiseCanExecuteChanged();
// assuming you could possibly have an UndoCommand somewhere
UndoCommand.RaiseCanExecuteChanged();
}

What kind of compiler magic do we need more?

I develop lot view models which are:
1) All have to implement INotifyPropertyChanged to be bindable to UI.
2) Property setters have to raise PropertyChanged on change.
3) PropertyChanged event has to provide proper property name.
If you (like me) tied of writing something like this:
public string Name
{
get
{
return _name;
}
set
{
if (_name != value)
{
_name = value;
RaisePropertyChanged("Name");
}
}
}
Then refactor this method like this and sometimes forget to update property name literal:
string _fundName;
public string FundName
{
get
{
return _fundName;
}
set
{
if (_fundName != value)
{
_fundName = value;
RaisePropertyChanged("Name");
}
}
}
And then spend a day to debug why your UI is not refreshing and databinding doesn't work properly.
Then all we need is some kind of magic.
What if I just need to write this:
[Magic] // implicit transformation
public string FundName { get; set; }
or if I have many properties:
[Magic]
public class MyViewModel
{
public string FundName { get; set; }
public string FundType { get; set; }
[NoMagic] // suppress transformation
public int InternalId { get; set; }
}
So I have just developed a MSBuild task to do this magic after the build (http://kindofmagic.codeplex.com).
The question is, what kind of magical postprocessing would you like more?
Does automatic implementation of INotifyPropertyChanging makes sense?
Try this
http://code.google.com/p/notifypropertyweaver/
No attributes required
No references required
No base class required
Here is my blog article about it
http://codesimonsays.blogspot.com/2010/11/attempting-to-solve-inotifypropertychan.html
It supports the attributes you request
NotifyPropertyAttribute (notify for a property)
NotifyForAllAttribute (notify for all properties on a type)
NotifyIgnoreAttribute (do not notify for a property or type)
AlsoNotifyFor (Allows the injection of notify code that points to a different property)
Although these are option and designed for fine tuning. Most injection is done by convention through analyzing the existing IL.
If we're going to have fancy code generation, I think I would prefer a way to generate DependancyProperties more easily. The snippit I use is certainly helpful, but I'm not a fan how jumbled the code looks when you have on-changed and coerce callbacks, and metadata options. Maybe I'll try and mock up a sample after work.
Edit: Well, here's one concept. It would look a lot more clever if you pass anonymous methods to attributes, but it's still a step up.
Before:
[DpDefault("The Void")]
[DpCoerce(new CoerceValueCallback(MainWindow.CoerceAddress))]
[DpChanged(new PropertyChangedCallback(MainWindow.ChangeAddress1))]
[DpChanged(new PropertyChangedCallback(MainWindow.ChangeAddress2))]
[DpOptions(FrameworkPropertyMetadataOptions.Inherits)]
public string Address {
get { return Dp.Get<string>(); }
set {
if (Dp.Get<string>() != value) {
Dp.Set(value);
PostOffice.SendMailToTheBoss("I moved!");
}
}
}
After:
public string Address {
get { return (string)GetValue(AddressProperty); }
set {
if ((string)GetValue(AddressProperty) != value) {
SetValue(AddressProperty, value);
PostOffice.SendMailToTheBoss("I moved!");
}
}
}
public static readonly DependencyProperty AddressProperty =
DependencyProperty.Register("Address", typeof(string), typeof(MainWindow),
new FrameworkPropertyMetadata((string)"The Void",
FrameworkPropertyMetadataOptions.Inherits,
new PropertyChangedCallback(MainWindow.ChangeAddress1)
+ new PropertyChangedCallback(MainWindow.ChangeAddress2),
new CoerceValueCallback(MainWindow.CoerceAddress)));
Typically, only the 'DpDefault' attribute would be used, but even if it doesn't make the code shorter, it certainly makes it clearer. Here would be a more typical example:
Before:
[DpDefault("The Void")]
public string Address { get; set; }
After:
public string Address {
get { return (string)GetValue(AddressProperty); }
set { SetValue(AddressProperty, value); }
}
public static readonly DependencyProperty AddressProperty =
DependencyProperty.Register("Address", typeof(string), typeof(MainWindow),
new UIPropertyMetadata((string)"The Void"));
"Magic" is almost always a terrible name for method or property or variable in any language. You should rename the attribute to something more descriptive. Imagine you are just a random internet pedestrian and stumble on a piece code with attribute "Magic", what does it tell you about the code? Exactly nothing :)
I will try your code anyways, it has potential to be quite a timesaver. This should definitely be a part of .NET.
Something that might make your life a little easier is this... (Ive picked it up from Caliburn Micro).
public virtual void NotifyOfPropertyChange<TProperty>(Expression<Func<TProperty>> property) {
NotifyOfPropertyChange(property.GetMemberInfo().Name);
}
This enables you to do the following..
NotifyOfProperyChange(() =>
this.PropertyName);
This will highlight any issues with the code at design time, rather than run time.
Caliburn Micro is an awesome little framework that you should take a look at, it removes so much of the wiring up involved with MVVM and Silverlight / WPF!
This can already be done using a AOP (Aspect Oriented Programming) tool like PostSharp : http://www.richard-banks.org/2009/02/aspect-oriented-programming.html (using v1.x)
http://www.sharpcrafters.com/solutions/ui#data-binding (using v2.0)
I used PostSharp to implement INPC in few projects and it worked out pretty well, the code is much more cleaner and maintainable (it adds a few seconds to compile time)

CollectionViewSource Filtering logic

The design I've come up with for filtering is awkward at best, and buggy at worst. The idea is to have a base class to support a pick list, and let subclasses add on additional filtering logic as needed.
What is particularly confusing to me is how to trigger the view to filter as various filtering criteria change (see _ApplyFiler(), below). Is setting the filter that way appropriate? Where should I unsubscribe / set it to null after it filters?
Cheers,
Berryl
ugly code:
public class SubjectPickerBase<T> : ViewModelBase, ISubjectPicker<T>
where T : class, IAvailableItem, INotifyPropertyChanged, IActivitySubject
{
public CollectionViewSource Subjects { get; private set; }
protected SubjectPickerBase() { }
protected void _Initialize(IEnumerable<T> subjects, string subjectName) {
...
Subjects = new CollectionViewSource { Source = subjects };
_ApplyFilter();
}
protected void _ApplyFilter() {
Subjects.View.Filter += Filter;
}
private bool Filter(object obj)
{
var subject = obj as T;
if (ReferenceEquals(subject, null)) return false;
NotifyPropertyChanged(() => Status);
var isIncludedBySubclass = OnFilter(subject);
var isIncludedByBase = subject.IsAvailable;
return isIncludedByBase & isIncludedBySubclass;
}
/// <summary>Hook to allow implementing subclass to provide it's own filter logic</summary>
protected virtual bool OnFilter(T subject) { return true; }
}
public class ProjectSelectionViewModel : SubjectPickerBase<ProjectViewModel>
{
public ProjectSelectionViewModel(IEnumerable<ProjectViewModel> projects)
{
...
_Initialize(projects, Strings.ActivitySubject__Project);
}
public string DescriptionMatchText {
get { return _descriptionMatchText; }
set {
ApplyPropertyChange<ProjectSelectionViewModel, string>(ref _descriptionMatchText, x => x.DescriptionMatchText, value);
_ApplyFilter();
}
}
private string _descriptionMatchText;
protected override bool OnFilter(ProjectViewModel subject)
{
...
var isDescriptionMatch = subject.IsMatch_Description(DescriptionMatchText);
return isPrefixMatch && isMidfixMatch && isSequenceNumberMatch && isDescriptionMatch;
}
}
There are several pieces to a non-trivial manipulation of the view that I was missing, all having to do with refreshing the CollectionView that is a property of the CollectionViewSource:
Refresh
DeferRefresh
NeedsRefresh
IsRefreshDeferred
The first part of my question was when to set the filter. For my use case, what worked best so far turned out to be registering for the CollectionViewSource.Filter event and then using the View.Refresh method each time a filter is changed. The initial registration of the filter event also triggers the event handler, and many of the msdn samples you see show this as a way of filtering a view, and nothing else. But if your scenario is not trivial & the user can change some filter criteria, you need to use one or more of the above refresh related methods & properties.
The second part of my question had to do with whether you needed to unsubscribe to the filter event, and if so, when. Well, it turns out that you don't need to unsubscribe, but if you do so it effectively clears any filtering of the view. And many of the msdn trivial samples do exactly that to clear the filter, which is certainly the way to go if you want to completely clear any filtering, but for my use case was not what I really wanted. What I wanted was to clear some criteria but not others, and so again using Refresh (at the right time) gave me the desired behavior.
HTH,
Berryl

WPF - Reload an a collection (with 'new') without rebinding controls

Imagine the following:
class Repository
{
private ObservableCollection<ModelClass> _allEntries;
public ObservableCollection<ModelClass> AllEntries
{
get { return _allEntries; }
set { _allEntries = value; }
}
public void RefreshDataFromDB()
{
_all = new ObservableCollection(GetMyData()); // whatever method there is
}
}
Now there are a couple of controls that bind to this collection, e.g.:
<ListView ItemsSource="{Binding Repository.AllEntries, ElementName=Whatever}"/>
The problem now is that if I call the RefreshDataFromDB the bindings get lost (at least it seems so) as the _all is now pointing to new memory part and the bindings still use the old reference. INotifyPropertyChanged does not help me in this case (e.g. putting it in RefreshDataFromDB does not help a lot).
The question would be - how would you handle a case where you replce a collection and want to update its consumers' bindings?
Yes; you're not modifying the collection, the UI is bound to the collection, and then you replace it with a new one.
You could do this:
_all.Clear();
_all.AddRange(GetMyData());
Hope that helps!
Alternatively, make AllEntries (or All.. your nomenclature seems to change a few times on the post ;)) a DependencyProperty:
public static DependencyProperty AllEntriesProperty = DependencyProperty.Register("AllEntries", typeof(ObservableCollection), typeof(MyClass));
You'd need to make the get/set property too, see here for an example:
http://msdn.microsoft.com/en-us/library/ms752914.aspx

Resources