I am working on WPF (MVVM) ..
using this tutorial :
https://www.tutorialspoint.com/mvvm/mvvm_validations.htm
when trying to implement "AddEditCustomerViewModel"
I received two errors for this class:
namespace MVVMHierarchiesDemo.ViewModel
{
class AddEditCustomerViewModel : BindableBase
{
public AddEditCustomerViewModel()
{
CancelCommand = new MyICommand(OnCancel);
SaveCommand = new MyICommand(OnSave, CanSave);
}
private bool _EditMode;
public bool EditMode
{
get { return _EditMode; }
set { SetProperty(ref _EditMode, value); }
}
private SimpleEditableCustomer _Customer;
public SimpleEditableCustomer Customer
{
get { return _Customer; }
set { SetProperty(ref _Customer, value); }
}
private Customer _editingCustomer = null;
public void SetCustomer(Customer cust)
{
_editingCustomer = cust;
if (Customer != null) Customer.ErrorsChanged -= RaiseCanExecuteChanged;
Customer = new SimpleEditableCustomer();
Customer.ErrorsChanged += RaiseCanExecuteChanged;
CopyCustomer(cust, Customer);
}
private void RaiseCanExecuteChanged(object sender, EventArgs e)
{
SaveCommand.RaiseCanExecuteChanged();
}
public MyICommand CancelCommand { get; private set; }
public MyICommand SaveCommand { get; private set; }
public event Action Done = delegate { };
private void OnCancel()
{
Done();
}
private async void OnSave()
{
Done();
}
private bool CanSave()
{
return !Customer.HasErrors;
}
}
}
First one;on this lines :
CancelCommand = new MyICommand(OnCancel);
SaveCommand = new MyICommand(OnSave, CanSave);
an error appear on MyICommand constructor as in :
Error CS0305 Using the generic type 'MyICommand' requires 1 type
arguments
Second one , on this line :
CopyCustomer(cust, Customer);
an error appear for CopyCustomer function as in :
Error CS0103 The name 'CopyCustomer' does not exist in the current
context
the implementation of MyICommand as in :
public class MyICommand<T> : ICommand
{
Action<T> _TargetExecuteMethod;
Func<T, bool> _TargetCanExecuteMethod;
public MyICommand(Action<T> executeMethod)
{
_TargetExecuteMethod = executeMethod;
}
public MyICommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod)
{
_TargetExecuteMethod = executeMethod;
_TargetCanExecuteMethod = canExecuteMethod;
}
public void RaiseCanExecuteChanged()
{
CanExecuteChanged(this, EventArgs.Empty);
}
#region ICommand Members
bool ICommand.CanExecute(object parameter)
{
if (_TargetCanExecuteMethod != null)
{
T tparm = (T)parameter;
return _TargetCanExecuteMethod(tparm);
}
if (_TargetExecuteMethod != null)
{
return true;
}
return false;
}
// Beware - should use weak references if command instance lifetime is
//longer than lifetime of UI objects that get hooked up to command
// Prism commands solve this in their implementation
public event EventHandler CanExecuteChanged = delegate { };
void ICommand.Execute(object parameter)
{
if (_TargetExecuteMethod != null)
{
_TargetExecuteMethod((T)parameter);
}
}
#endregion
}
}
to see the whole Project folder ; please see this link :
https://drive.google.com/drive/folders/1jFDU6vDMW_TO0J88NT53oLVWVYbAYyTv?usp=sharing
Related
I have a view which opens an idialog that I contain a datagrid. I select certain rows and send back those as a list to the view but all I search I just found ResultButton return for idialog. How I can send back a custom value like a list or anything else ?
My iDialog ViewModel :
public DelegateCommand<string> CloseCommand { get; set; }
public DelegateCommand<string> AttachCommand { get; set; }
private string _txtSearch;
public string txtSearch
{
get { return _txtSearch; }
set { SetProperty(ref _txtSearch, value); }
}
public List<GE_Drawing> SelectedDrawings { get; set; }
private ObservableCollection<GE_Drawing> _DrawingList= new ObservableCollection<GE_Drawing>();
public ObservableCollection<GE_Drawing> DrawingList
{
get { return _DrawingList; }
set { SetProperty(ref _DrawingList, value); }
}
private bool _IsSelected;
public bool IsSelected
{
get { return _IsSelected; }
set { SetProperty(ref _IsSelected, value); }
}
public GE_DrawingAttachViewModel()
{
LoadList();
CloseCommand = new DelegateCommand<string>(onClose);
AttachCommand = new DelegateCommand<string>(onAttach);
}
private void onAttach(string parameter)
{
ButtonResult result = new ButtonResult();
var records = DrawingList.Where(x => x.IsSelected == true).ToList();
if(records.Count>0)
{
SelectedDrawings = records;
}
//result = ButtonResult.OK;
//RaiseRequestClose(new DialogResult(result));
}
private void RaiseRequestClose(DialogResult dialogResult)
{
RequestClose?.Invoke(dialogResult);
}
private void onClose(string parameter)
{
ButtonResult result = new ButtonResult();
result = ButtonResult.Cancel;
RaiseRequestClose(new DialogResult(result));
}
private string _title="Drawing List";
public string Title
{
get => _title;
set => SetProperty(ref _title, value);
}
public event Action<IDialogResult> RequestClose;
public bool CanCloseDialog()
{
return true;
}
public void OnDialogClosed()
{
}
public void OnDialogOpened(IDialogParameters parameters)
{
}
public async void LoadList()
{
GenericDataService<GE_Drawing> generic = new GenericDataService<GE_Drawing>();
DrawingList.AddRange(await generic.GetAll());
}
}
As written above I have an OnAttach which should send back my SelectedDrawings variable to the view but I dont know how to do that.
I have found the answer... IdialogResult have parameter with a value could be set to in dialog and get the value in the callback using a key.
private void openDialog()
{
DialogParameters parameter = new DialogParameters();
_dialogService.ShowDialog("GE_DrawingAttach", parameter, r =>
{
if(r.Result==ButtonResult.OK)
{
DrawingList = r.Parameters.GetValue<List<GE_Drawing>>("DrawingList");
}
});
}
The following code is an example to explain my issue.
I have a textbox in binding. When I click on a button, executes a function. (In this case it's a for loop).
Now I want, the text box updated with the content of the i variable. (public void MyAction())
So, I made a thread, but this doesn't work.
Why ?
Thanks in advance
XAML code
<TextBox Text ="{Binding MyValue}" HorizontalAlignment="Left" Height="47" Margin="4,4,4,4" VerticalAlignment="Top" Width="342"/>
<Button Command="{Binding ClickCommand}" Content="Run" Margin="114,69,283,216"/>
C# code
class Vm_Main : ViewModelBase
{
public string _MyValue { get; set; } //String in my XAML
public string MyValue
{
get { return _MyValue; }
set
{
_MyValue = value;
base.OnPropertyChanged("MyValue");
}
}
private bool _canExecute=true;
private ICommand _clickCommand;
public ICommand ClickCommand
{
get
{
return _clickCommand ?? (_clickCommand = new CommandHandler(() => MyAction(), _canExecute));
}
}
public Vm_Main()
{
MyValue = "Hallo"; //Default value
}
public void MyAction() // This is the function where I want update the TextBox in Binding
{
Worker workerObject = new Worker();
Thread workerThread = new Thread(workerObject.DoWork);
workerThread.Start();
for (int i = 1; i <= 10; i++)
{
MyValue = i.ToString();
workerObject.Value = MyValue;
Thread.Sleep(500);
}
workerObject.RequestStop();
workerThread.Join();
MessageBox.Show("End");
}
}
// The THREAD
public class Worker : ViewModelBase
{
// This method will be called when the thread is started.
public string _Value { get; set; }
public string Value
{
get { return _Value; }
set
{
_Value = value;
base.OnPropertyChanged("Value");
}
}
public void DoWork()
{
while (!_shouldStop)
{
Console.WriteLine("Value is..." + _Value);
}
Console.WriteLine("End.");
}
public void RequestStop()
{
_shouldStop = true;
}
// Volatile is used as hint to the compiler that this data
// member will be accessed by multiple threads.
private volatile bool _shouldStop;
}
And Class ViewModelBase and Class Command
public abstract class ViewModelBase : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string strPropertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(strPropertyName));
}
#endregion
#region Messages and Progressbar
private string _errorMessage;
public string ErrorMessage
{
get { return _errorMessage; }
set
{
if (_errorMessage == value) return;
_errorMessage = value;
OnPropertyChanged("ErrorMessage");
}
}
private string _errorTooltip;
public string ErrorTooltip
{
get { return _errorTooltip; }
set
{
if (_errorTooltip == value) return;
_errorTooltip = value;
this.OnPropertyChanged("ErrorTooltip");
}
}
private string _statusMessage;
public string StatusMessage
{
get { return _statusMessage; }
set
{
if (_statusMessage == value) return;
_statusMessage = value;
//pulizia dei messaggi di errore
ErrorMessage = string.Empty;
ErrorTooltip = string.Empty;
OnPropertyChanged("StatusMessage");
}
}
protected void ClearMessage()
{
ErrorMessage = string.Empty;
StatusMessage = string.Empty;
}
private int _currentProgress;
public int CurrentProgress
{
get { return _currentProgress; }
set
{
_currentProgress = value;
OnPropertyChanged("CurrentProgress");
}
}
#endregion
protected ViewModelBase()
{
}
}
public class CommandHandler : ICommand
{
private Action _action;
private bool _canExecute;
public CommandHandler(Action action, bool canExecute)
{
_action = action;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_action();
}
}
So I think you have to issues.
First use async await pattern.
It goes like this - to not block ur UI thread.
public async Task<object> MyAsyncMethod()
{
return await Task.Run<object>(() =>
{
return null;
});
}
or for ICommand just:
public async void MyAsyncMethod()
{
await Task.Run(() =>
{
});
}
Second is that you may want to update your UI - while processing async. This is a common problem for updating progress for example. You can solve this with SynchronizationContext.
public interface IUpdateProgess
{
void SendMessage(string val);
}
public async Task<object> MyAsyncMethod(IUpdateProgess progress)
{
//UI thread
SynchronizationContext context = SynchronizationContext.Current;
return await Task.Run<object>(() =>
{
//other thread
if (context != null && progress != null)
{
context.Post(new SendOrPostCallback((o) =>
{
progress.SendMessage("Progress");
}), null);
}
return null;
});
}
You can use this obviously to not just update progress - i think you get the idea.
I have a MvxDialogFragment and I want to show that using ViewModel, similarly when a activity is showed from ViewModel using ShowViewModel. Is it possible? How can I do that?
This is my scenario: I have a page that contains a MvxListView and, when the user click in a listview item, I want to show a MvxDialogFragment.
My ListView layout:
<Mvx.MvxListView
android:id="#+id/lstViewTasks"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:dividerHeight="1px"
android:clickable="true"
android:focusableInTouchMode="true"
android:choiceMode="multipleChoice"
android:layout_alignParentTop="true"
local:MvxBind="ItemsSource Tasks; ItemClick ItemClickCommand"
local:MvxItemTemplate="#layout/projectmytasksitem" />
My ListView ViewModel:
public class ProjectMyTasksViewModel : MvxViewModel
{
#region [Atributos privados]
private ProjectService _service;
#endregion
#region [Propriedades]
private IList<Task> _tasks;
public IList<Task> Tasks
{
get { return _tasks; }
set { _tasks = value; RaisePropertyChanged(() => Tasks); }
}
private bool _isListaVazia;
public bool IsListaVazia
{
get { return _isListaVazia; }
set { _isListaVazia = value; RaisePropertyChanged(() => IsListaVazia); }
}
private Task _selectedTask;
public Task SelectedTask
{
get { return _selectedTask; }
set { _selectedTask = value; RaisePropertyChanged(() => SelectedTask); }
}
private string _mensagemErro;
public string MensagemErro
{
get { return _mensagemErro; }
set { _mensagemErro = value; RaisePropertyChanged(() => MensagemErro); }
}
#endregion
#region [Commands]
private IMvxCommand _itenClickCommand;
public IMvxCommand ItemClickCommand
{
get
{
this._itenClickCommand = this._itenClickCommand ?? new MvxCommand<Task>(this.ExecuteItemClickCommand);
return _itenClickCommand;
}
}
#endregion
#region [Construtores]
public ProjectMyTasksViewModel()
{
_service = new ProjectService();
this.CriaListaTeste();
IsListaVazia = (Tasks.Count > 0) ? true : false;
}
#endregion
#region [Execuções dos Comandos]
private void ExecuteItemClickCommand(Task task)
{
Dictionary<string, Task> parametros = new Dictionary<string, Task>()
{
{"Task", task }
};
this.ShowViewModel<TaskViewModel>(parametros);
}
#endregion
#region [Métodos]
public void CriaListaTeste()
{
Tasks = new List<Task>();
for (int indiceProjeto = 1; indiceProjeto <= 10; indiceProjeto++)
{
Tasks.Add(new Task { Name = $"Tarefa {indiceProjeto}", StartDate = DateTime.Now, FinishDate = DateTime.Now, IsCompleted = false });
}
}
#endregion
}
My Listview Activity:
[Activity(Label = "My Task",
ConfigurationChanges = ConfigChanges.Orientation,
ScreenOrientation = ScreenOrientation.Portrait)]
public class ProjectMyTasksView : MvxActivity
{
public new ProjectMyTasksViewModel viewModel
{
get { return (ProjectMyTasksViewModel)base.ViewModel; }
set { base.ViewModel = value; }
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
this.SetContentView(Resource.Layout.ProjectMyTasksView);
}
}
My Dialog Fragment:
public class ProjectMyTaskDialog : MvxDialogFragment<TaskViewModel>
{
public override Dialog OnCreateDialog(Bundle savedState)
{
base.EnsureBindingContextSet(savedState);
this.BindingInflate(Resource.Layout.ProjectMyTasksDialog, null);
return base.OnCreateDialog(savedState);
}
}
My Dialog Fragment ViewModel:
public class TaskViewModel : BaseViewModel<TaskService, Task>
{
#region [Atributos Privados]
private readonly IMvxPictureChooserTask _pictureChooserTask;
#endregion
#region [Commands]
private MvxCommand _chooseImageCommand;
public MvxCommand ChooseImageCommand
{
get
{
_chooseImageCommand = _chooseImageCommand ?? new MvxCommand(ExecuteChooseImageCommand);
return _chooseImageCommand;
}
}
private MvxCommand _takePictureCommand;
public MvxCommand TakePictureCommand
{
get
{
_takePictureCommand = _takePictureCommand ?? new MvxCommand(ExecuteTakePictureCommand);
return _takePictureCommand;
}
}
private MvxCommand _completeTaskCommand;
public MvxCommand CompleteTaskCommand
{
get
{
_completeTaskCommand = _completeTaskCommand ?? new MvxCommand(ExecuteCompleteTaskCommand);
return _completeTaskCommand;
}
}
#endregion
#region [Construtores]
public TaskViewModel(IMvxPictureChooserTask pictureChooserTask)
{
_pictureChooserTask = pictureChooserTask;
}
#endregion
#region [Execuções dos Comandos]
private void ExecuteChooseImageCommand()
{
_pictureChooserTask.ChoosePictureFromLibrary(400, 95, OnImage, () => { });
}
private void ExecuteTakePictureCommand()
{
_pictureChooserTask.TakePicture(400, 95, OnImage, () => { });
}
public void ExecuteCompleteTaskCommand()
{
throw new NotImplementedException();
}
#endregion
#region [Métodos]
public void Init(Dictionary<string, Task> parametros)
{
Objeto = parametros["Task"];
}
private void OnImage(Stream imageStream)
{
var memoryStream = new MemoryStream();
imageStream.CopyTo(memoryStream);
Objeto.Image = memoryStream.ToArray();
}
#endregion
public class Parametros
{
public string TaskJson { get; set; }
}
}
There is no presenter for DialogFragments.
Instead you could have instantiate the Command from the Activity or have a callback into the Activity which determines what to do when the command is called, i.e. displaying the Dialog.
So for a simple example:
public class MyViewModel : MvxViewModel
{
public Action ShowTaskCommandAction {get;set;}
private MvxCommand _showTaskCommand;
public ICommand ShowTaskCommand =>
_showTaskCommand = _showTaskCommand ?? (_showTaskCommand = new MvxCommand(DoShowTaskCommand));
private void DoShowTaskCommand()
{
CommandAction?.Invoke();
// do other stuff here...
}
}
Then in your Activity or Fragment:
public class MyActivity : MvxActivity<MyViewModel>
{
public void OnCreate(Bundle _)
{
base.OnCreate(_);
ViewModel.ShowTaskCommandAction = () => {
var dialogFragment = new ProjectMyTaskDialog() {
DataContext = task
});
dialogFragment.Show(FragmentManager);
};
// whatever else code
}
}
What is the best way to create a class with an event that fires when one of its Properties is changed? Specifically, how do you convey to any subscribers which Property was changed?
Ex:
public class ValueChangedPublisher
{
private int _prop1;
private string _prop2;
public static event ValueChangedHandler(/*some parameters?*/);
public int Prop1
{
get { return _prop1; }
set
{
if (_prop1 != value)
{
_prop1 = value;
ValueChangedHandler(/*parameters?*/);
}
}
}
public string Prop2
{
get { return _prop2; }
set
{
if (_prop2 != value)
{
_prop2 = value;
ValueChangedHandler(/*parameters?*/);
}
}
}
}
public class ValueChangedSubscriber
{
private int _prop1;
private string _prop2;
public ValueChangedSubscriber()
{
ValueChangedPublisher.ValueChanged += ValueChanged;
}
private void ValueChanged(/*parameters?*/)
{
/*how does the subscriber know which property was changed?*/
}
}
My goal is to make this as extensible as possible (e.g. I don't want a bunch of huge if/else if/switch statements lumbering around). Does anybody know of a technique to achieve what I'm looking for?
EDIT:
What I'm really looking for is how to utilize the INotifyPropertyChanged pattern on the subscriber side. I don't want to do this:
private void ValueChanged(string propertyName)
{
switch(propertyName)
{
case "Prop1":
_prop1 = _valueChangedPublisher.Prop1;
break;
case "Prop2":
_prop2 = _valueChangedPublisher.Prop2;
break;
// the more properties that are added to the publisher, the more cases I
// have to handle here :/ I don't want to have to do it this way
}
}
.NET provides the INotifyPropertyChanged interface. Inherit and implement it:
public class ValueChangedPublisher : INotifyPropertyChanged
{
private int _prop1;
private string _prop2;
public event PropertyChangedEventHandler ValueChangedHandler;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public int Prop1
{
get { return _prop1; }
set
{
if (_prop1 != value)
{
_prop1 = value;
NotifyPropertyChanged();
}
}
}
public string Prop2
{
get { return _prop2; }
set
{
if (_prop2 != value)
{
_prop2 = value;
NotifyPropertyChanged();
}
}
}
}
Here is what I did to solve my problem. It's a bit large, so maybe not performant, but works for me.
Edit
See this question for performance details: C# using properties with value types with Delegate.CreateDelegate
Base Class for publishing property change stuff:
public abstract class PropertyChangePublisherBase : INotifyPropertyChanged
{
private Dictionary<string, PropertyInfo> _properties;
private bool _cacheProperties;
public bool CacheProperties
{
get { return _cacheProperties; }
set
{
_cacheProperties = value;
if (_cacheProperties && _properties == null)
_properties = new Dictionary<string, PropertyInfo>();
}
}
protected PropertyChangePublisherBase(bool cacheProperties)
{
CacheProperties = cacheProperties;
}
public bool ContainsBinding(PropertyChangedEventHandler handler)
{
if (PropertyChanged == null)
return false;
return PropertyChanged.GetInvocationList().Contains(handler);
}
public object GetPropertValue(string propertyName)
{
if (String.IsNullOrEmpty(propertyName) || String.IsNullOrWhiteSpace(propertyName))
throw new ArgumentException("Argument must be the name of a property of the current instance.", "propertyName");
return ProcessGetPropertyValue(propertyName);
}
protected virtual object ProcessGetPropertyValue(string propertyName)
{
if (_cacheProperties)
{
if (_properties.ContainsKey(propertyName))
{
return _properties[propertyName].GetValue(this, null);
}
else
{
var property = GetType().GetProperty(propertyName);
_properties.Add(propertyName, property);
return property.GetValue(this, null);
}
}
else
{
var property = GetType().GetProperty(propertyName);
return property.GetValue(this, null);
}
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
Base Class for receiving property change stuff:
public abstract class PropertyChangeSubscriberBase
{
protected readonly string _propertyName;
protected virtual object Value { get; set; }
protected PropertyChangeSubscriberBase(string propertyName, PropertyChangePublisherBase bindingPublisher)
{
_propertyName = propertyName;
AddBinding(propertyName, this, bindingPublisher);
}
~PropertyChangeSubscriberBase()
{
RemoveBinding(_propertyName);
}
public void Unbind()
{
RemoveBinding(_propertyName);
}
#region Static Fields
private static List<string> _bindingNames = new List<string>();
private static List<PropertyChangeSubscriberBase> _subscribers = new List<PropertyChangeSubscriberBase>();
private static List<PropertyChangePublisherBase> _publishers = new List<PropertyChangePublisherBase>();
#endregion
#region Static Methods
private static void PropertyChanged(object sender, PropertyChangedEventArgs args)
{
string propertyName = args.PropertyName;
if (_bindingNames.Contains(propertyName))
{
int i = _bindingNames.IndexOf(propertyName);
var publisher = _publishers[i];
var subscriber = _subscribers[i];
subscriber.Value = publisher.GetPropertValue(propertyName);
}
}
public static void AddBinding(string propertyName, PropertyChangeSubscriberBase subscriber, PropertyChangePublisherBase publisher)
{
if (!_bindingNames.Contains(propertyName))
{
_bindingNames.Add(propertyName);
_publishers.Add(publisher);
_subscribers.Add(subscriber);
if (!publisher.ContainsBinding(PropertyChanged))
publisher.PropertyChanged += PropertyChanged;
}
}
public static void RemoveBinding(string propertyName)
{
if (_bindingNames.Contains(propertyName))
{
int i = _bindingNames.IndexOf(propertyName);
var publisher = _publishers[i];
_bindingNames.RemoveAt(i);
_publishers.RemoveAt(i);
_subscribers.RemoveAt(i);
if (!_publishers.Contains(publisher))
publisher.PropertyChanged -= PropertyChanged;
}
}
#endregion
}
Actual class to use for subscribing to property change stuff:
public sealed class PropertyChangeSubscriber<T> : PropertyChangeSubscriberBase
{
private PropertyChangePublisherBase _publisher;
public new T Value
{
get
{
if (base.Value == null)
return default(T);
if (base.Value.GetType() != typeof(T))
throw new InvalidOperationException(String.Format("Property {0} on object of type {1} does not match the type Generic type specified {2}.", _propertyName, _publisher.GetType(), typeof(T)));
return (T)base.Value;
}
set { base.Value = value; }
}
public PropertyChangeSubscriber(string propertyName, PropertyChangePublisherBase bindingPublisher)
: base(propertyName, bindingPublisher)
{
_publisher = bindingPublisher;
}
}
Here is an example of the Class with properties that you wish to be notified about:
public class ExamplePublisher: PropertyChangedPublisherBase
{
private string _id;
private bool _testBool;
public string Id
{
get { return _id; }
set
{
if (value == _id) return;
_id = value;
RaisePropertyChanged("Id");
}
}
public bool TestBool
{
get { return _testBool; }
set
{
if (value.Equals(_testBool)) return;
_testBool = value;
RaisePropertyChanged("TestBool");
}
}
}
Here is an example of the Class that will be notified when the properties in the class above change:
public class ExampleReceiver
{
public PropertyChangeSubscriber<string> Id { get; set; }
public PropertyChangeSubscriber<bool> TestBool { get; set; }
public MyExampleClass(PropertyChangePublisherBase publisher)
{
Id = new PropertyChangeSubscriber<string>("Id", publisher);
TestBool = new PropertyChangeSubscriber<bool>("TestBool", publisher);
}
}
I am using this code to make a Simple Command:
public class SimpleCommand : ICommand
{
public Predicate<object> CanExecuteDelegate { get; set; }
public Action<object> ExecuteDelegate { get; set; }
#region ICommand Members
public bool CanExecute(object parameter)
{
if (CanExecuteDelegate != null)
return CanExecuteDelegate(parameter);
return true;// if there is no can execute default to true
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
if (ExecuteDelegate != null)
ExecuteDelegate(parameter);
}
#endregion
}
I did not write this. But I enjoy using it. When I use it it ends up being like this:
// This is the value that gets set to the command in the UI
public SimpleCommand DoSomethingCommand { get; set; }
public DoSomethingCommandConstructor()
{
DoSomethingCommand = new SimpleCommand
{
ExecuteDelegate = x => RunCommand(x)
};
}
private void RunCommand(object o)
{
// Run the command.
}
The only problem with this is that the parameter of RunCommand is an object. I think I have been spoiled by generics. I always want the IDE/compiler to just know what the type I am working with is with out casting.
Is it possible to change this SimpleCommand class to be implemented using generics?
Sure. Was gonna point you to Prism's implementation, but CodePlex source tab seems to not be working. It would look something like:
public class SimpleCommand<T> : ICommand
{
public Predicate<T> CanExecuteDelegate { get; set; }
public Action<T> ExecuteDelegate { get; set; }
#region ICommand Members
public bool CanExecute(object parameter)
{
if (CanExecuteDelegate != null)
return CanExecuteDelegate((T)parameter);
return true;// if there is no can execute default to true
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
if (ExecuteDelegate != null)
ExecuteDelegate((T)parameter);
}
#endregion
}
Incidentally, your usage of SimpleCommand in your question is a little roundabout. Instead of this:
DoSomethingCommand = new SimpleCommand
{
ExecuteDelegate = x => RunCommand(x)
};
You could just have:
DoSomethingCommand = new SimpleCommand
{
ExecuteDelegate = this.RunCommand
};
Specifying a lambda is really only useful if you're doing the work inline like this:
DoSomethingCommand = new SimpleCommand
{
ExecuteDelegate = o => this.SelectedItem = o,
CanExecuteDelegate = o => o != null
};