Linqpad checkbox update an instance problem - checkbox

I want to let the user check a list of checkboxes, and after that when clicking a button act on what was checked.
I defined an event for each check box, when its check is changed, the instance for which it was created will be updated:
void Main()
{
var fooList = new[] { 1, 2, 3 }.Select(num => new Foo { Id = num });
fooList.Select(foo => new CheckBox(foo.Id.ToString(), onClick: cb => foo.Status = cb.Checked)).Dump();
new Button("Show fooList updated", _ => fooList.Dump()).Dump(); //always all Status is false!
}
class Foo
{
public int Id { get; set; }
private bool _status = false;
public bool Status
{
get => _status;
set
{
_status = value;
value.Dump("now successed change value"); //printed!
}
}
}
The strange result is that the Status values are always false!

I found the problem...
The fooList is IEnumerable, so anyone who accesses it creates a completely new copy...
Adding ToArray() (In line 3) solved the mystery.

Related

ObservableCollection deep cloning

I've implemented deep cloning of ObservableCollection in order to reset items to It's original state in editable Datagrid, via cancel button.
For this I have two collections - one ObservableCollection to bind Datagrid to It, and cloned List to re-initialize ObservableCollection to It's original state when needed.
My code works only first time I hit a cancel button, after that my cloned List has changes in It too.
Provided code is an example (mine is a bit longer), but It's 100% same as mine:
Model, which implements ICloneable:
public class EmployeeModel : ICloneable
{
public object Clone()
{
return MemberwiseClone();
}
public string NAME
{
get { return _name; }
set
{
if (_name != value)
{
CHANGE = true;
_name = value;
}
}
}
private string _name;
public string SURNAME
{
get { return _surname; }
set
{
if (_surname != value)
{
CHANGE = true;
_surname = value;
}
}
}
private string _surname;
///<summary>Property for tracking changes in model</summary>
public bool CHANGE { get; set; }
}
Viewmodel:
public ViewModel() : Base //Implements InotifyPropertyChanged
{
public ViewModel()
{
Task.Run(()=> GetData());
}
public ObservableCollection<EmployeeModel> Employees
{
get { return _employees; }
set { _employees = value; OnPropertyChanged();}
}
private ObservableCollection<EmployeeModel> _employees;
public List<EmployeeModel> Copy_employees
{
get { return _copy_employees; }
set { _copy_employees = value; OnPropertyChanged();}
}
private List<EmployeeModel> _copy_employees;
//Fetch data from DB
private async Task Get_data()
{
//Returns new ObservableCollection of type Employee
Employees = await _procedures.Get_employees();
if (Employees != null) //Now make a deep copy of Collection
{
Copy_employees = new List<EmployeeModel>();
Copy_employees = Employees.Select(s => (EmployeeModel)s.Clone()).ToList();
}
}
//My Command for canceling changes (reseting DataGrid)
//CanExecute happens, when model is changed - tracking via CHANGE property of EmployeeModel
public void Cancel_Execute(object parameter)
{
Employees.Clear(); //Tried with re-initializing too, but same result
foreach (var item in Copy_employees)// Reset binded ObservableCollection with old items
{
Employees.Add(item);
}
//Check if copied List really hasn't got any changes
foreach (EmployeeModel item in Copy_employees)
{
Console.WriteLine("Changes are " + item.CHANGES.ToString());
}
}
}
Output of cancel command:
1.) First time I hit cancel button:
// Changes are False
Every next time:
// Changes are True
So, as I see It from Console, my copied List get's updated when ObservableColection get's updated, even if It's not binded to DataGrid.
And It updates only a property which I changed, so List reflects ObservableCollection items.
How can I keep my original items of List<Employee>, and copy those into binded ObservableCollection anytime ?
When you return values, you do not return them, but write backing item references to the editable collection.
As a result, you have the same instances in both collections.
In the simplest case, when you return them, you also need to clone.
public void Cancel_Execute(object parameter)
{
Employees.Clear(); //Tried with re-initializing too, but same result
foreach (var item in Copy_employees)// Reset binded ObservableCollection with old items
{
Employees.Add((EmployeeModel)item.Clone());
}
//Check if copied List really hasn't got any changes
foreach (EmployeeModel item in Copy_employees)
{
Console.WriteLine("Changes are " + item.CHANGES.ToString());
}
}
Not relevant to the question, but I still advise you to use a slightly more user-friendly interface for cloneable:
public interface ICloneable<T> : ICloneable
{
new T Clone();
}

Why is my Login button always disabled?

I have a popup view with x:Name=This, on it a button delcared as follows:
<Button Content="Log in" Command="{Binding Path=LoginCommand}" CommandParameter="{Binding ElementName=This}" />
This is to gain access to the non-bindable Password property, which is a SecureString type.
In my ctor I initialise the command like so:
public LoginPopupViewModel()
{
LoginCommand = new DelegateCommand<IHavePassword>(
LogUserIn,
p => !string.IsNullOrWhiteSpace(Username));
}
I fully expect that when I type something in the Username, and change focus, the property change notification will help enable the Login button. It doesn't, so I have added the extra code, and the button still remains disabled.
public string Username
{
get { return _username; }
set
{
if (value == _username) return;
_username = value;
OnPropertyChanged();
CommandManager.InvalidateRequerySuggested();
}
}
If I change the CanExecute delegate like below, only then is the button enabled:
public LoginPopupViewModel()
{
LoginCommand = new DelegateCommand<IHavePassword>(
LogUserIn,
p => true);
}
Why does this button remain disabled even when its command can execute?
I have tried a sample program and binding seems to work fine. I don't have your complete source code but you need to use RaiseCanExecuteChanged on the delegate command when you want the command to check if it needs to execute. Have you checked if the binding on the username is correct?
this.loginCommand.RaiseCanExecuteChanged(); is the key to the answer
public LoginPopupViewModel()
{
this.loginCommand = new DelegateCommand(() =>
{
MessageBox.Show("Logged In Click");
}, () =>
{
return !string.IsNullOrEmpty(UserName);
});
}
private DelegateCommand loginCommand;
private string userName;
public ICommand LoginCommand
{
get { return loginCommand; }
}
public string UserName
{
get { return this.userName; }
set
{
if (value == this.userName)
{
return;
}
this.userName = value;
OnPropertyChanged("UserName");
this.loginCommand.RaiseCanExecuteChanged();
}
}
public string Password { get; set; }

Paging ListBox with ReactiveUI and Caliburn.Micro

I'm trying to implement a paging mechanism for a listbox using Caliburn.Micro.ReactiveUI with a call to EF using ".Skip(currentPage).Take(pageSize)". I'm new to ReactiveUI and Reactive in general. I'm sure this is supposed to be easy.
I've got a single "SearchParameters" class which I needs to be observed and the search function needs to execute when any of the properties on the SearchParameters object changes.
You can see from the commented-out code that I've tried to define the class as a ReactiveObject as well. The current implementation though is with CM's PropertyChangedBase. The individual properties are bound textboxes in my view using CM's conventions:
public class SearchParameters : PropertyChangedBase
{
private string _searchTerm;
public string SearchTerm
{
get { return _searchTerm; }
set
{
if (value == _searchTerm) return;
_searchTerm = value;
NotifyOfPropertyChange(() => SearchTerm);
}
}
private int _pageSize;
public int PageSize
{
get { return _pageSize; }
set
{
if (value == _pageSize) return;
_pageSize = value;
NotifyOfPropertyChange(() => PageSize);
}
}
private int _skipCount;
public int SkipCount
{
get { return _skipCount; }
set
{
if (value == _skipCount) return;
_skipCount = value;
NotifyOfPropertyChange(() => SkipCount);
}
}
//private string _searchTerm;
//public string SearchTerm
//{
// get { return _searchTerm; }
// set { this.RaiseAndSetIfChanged(ref _searchTerm, value); }
//}
//private int _pageSize;
//public int PageSize
//{
// get { return _pageSize; }
// set { this.RaiseAndSetIfChanged(ref _pageSize, value); }
//}
//private int _skipCount;
//public int SkipCount
//{
// get { return _skipCount; }
// set { this.RaiseAndSetIfChanged(ref _skipCount, value); }
//}
}
"SearchService" has the following method which needs to execute when any one of SearchParameter's values change:
public async Task<SearchResult> SearchAsync(SearchParameters searchParameters)
{
return await Task.Run(() =>
{
var query = (from m in _hrEntities.Departments select m);
if (!String.IsNullOrEmpty(searchParameters.SearchTerm))
{
searchParameters.SearchTerm = searchParameters.SearchTerm.Trim();
query = query.Where(
x => x.Employee.LastName.Contains(searchParameters.SearchTerm) || x.Employee.FirstName.Contains(searchParameters.SearchTerm)).Skip(searchParameters.SkipCount).Take(searchParameters.PageSize);
}
return new SearchResult
{
SearchTerm = searchParameters.SearchTerm,
Matches = new BindableCollection<DepartmentViewModel>(query.Select(x => new DepartmentViewModel{ Department = x }).Skip(searchParameters.SkipCount).Take(searchParameters.PageSize))
};
});
}
Here's how I've tried to wire all of this up in MainViewModel's ctor and where Rx gets hazy for me:
public class MainViewModel : ReactiveScreen
{
private SearchParameters _searchParameters;
public SearchParameters SearchParameters
{
get { return _searchParameters; }
set
{
if (value == _searchParameters) return;
_searchParameters = value;
NotifyOfPropertyChange(() => SearchParameters);
}
}
{
public void MainViewModel()
{
var searchService = new SearchService();
//default Skip and PageSize values
SearchParameters = new Services.SearchParameters { SkipCount = 0 , PageSize = 10};
var searchParameters = this.ObservableForProperty(x => x.SearchParameters)
.Value()
.Throttle(TimeSpan.FromSeconds(.3));
var searchResults = searchParameters.SelectMany(parameters => searchService.SearchAsync(parameters));
var latestMatches = searchParameters
.CombineLatest(searchResults,
(searchParameter, searchResult) =>
searchResult.SearchTerm != searchParameter.SearchTerm
? null
: searchResult.Matches)
.Where(matches => matches != null);
_departmentViewModels = latestMatches.ToProperty(this, x => x.DepartmentViewModels);
searchParameters.Subscribe(x => Debug.WriteLine(x));
}
}
In the above example the call to SearchAsync doesn't execute. It seems that changes to SearchParameter's properties aren't being observed.
Can anyone tell me what I'm doing wrong here?
Here's how I ended up doing this although I'd be interested in hearing other solutions if anyone has suggestions. I'm not sure if this is the best way but it works:
First, I defined a computed property in my SearchParameters class that returns a string and reevaluates anytime CurrentPage, SkipCount and PageSize are updated from the View:
public string ParameterString
{
get { return String.Format("SearchTerm={0}|SkipCount={1}|PageSize={2}", SearchTerm, SkipCount, PageSize); }
}
Next, in my MainViewModel ctor I simply observe the computed rather than attempting to react to SearchTerm, SkipCount and PageSize individually (which my original question was asking how to do):
var searchTerms = this
.ObservableForProperty(x => x.SearchParameters.ParameterString)
.Value()
.Throttle(TimeSpan.FromSeconds(.3));
var searchResults = searchTerms.SelectMany(parameters => SearchService.SearchAsync(parameters));
var latestMatches = searchTerms
.CombineLatest(searchResults,
(searchTerm, searchResult) =>
searchResult.SearchTerm != searchTerm
? null
: searchResult.Matches)
.Where(matches => matches != null);
Finally, in my SearchService I parse the parameter string to get the current values:
var parameters = searchParameters.Split('|');
var searchTerm = "";
var skipCount = 0;
var pageSize = 0;
foreach (var parameter in parameters)
{
if (parameter.Contains("SearchTerm="))
{searchTerm = parameter.Replace("SearchTerm=", "");}
else if (parameter.Contains("SkipCount="))
{ skipCount = Convert.ToInt32(parameter.Replace("SkipCount=", "")); }
else if (parameter.Contains("PageSize="))
{ pageSize = Convert.ToInt32(parameter.Replace("PageSize=", "")); }
}

JavaFX 8: ComboBox button cell update behavior

I have a combo box which contains items of type Dog. If all items are replaced with new ones (via setAll on the ObservableList model) , the item renderer can cope with this update, while the button cell renderer cannot:
Here's a minimal example to reproduce the problem (full source incl. imports on GitHub):
public class ComboBoxRefresh extends Application {
private static final class Dog {
private final String name;
public Dog(String name) {
this.name = name;
}
}
private static final class DogListCell extends ListCell<Dog> {
#Override
public void updateItem(Dog item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText("");
} else {
setText(item.name);
}
}
}
private static List<Dog> createThreeDogs() {
return range(0, 3).mapToObj(i -> new Dog("Buddy " + i)).collect(toList());
}
#Override
public void start(Stage stage) throws Exception {
ObservableList<Dog> items = observableArrayList(createThreeDogs());
ComboBox<Dog> comboBox = new ComboBox<>(items);
comboBox.setPrefWidth(400);
comboBox.setCellFactory(listView -> new DogListCell());
comboBox.setButtonCell(new DogListCell());
Button button = new Button("Refresh");
button.setOnAction(event -> {
List<Dog> newItems = createThreeDogs();
items.setAll(newItems);
});
VBox box = new VBox(10, comboBox, button);
box.setPadding(new Insets(10));
Scene scene = new Scene(box);
stage.setScene(scene);
stage.show();
}
}
If I add an equals implementation to the Dog class, everything works, but this is not an option in my real application.
Are there any work-arounds to enforce a proper refresh of the button cell?
It seems to be a bug. Workaround could be
button.setOnAction( event -> {
List<Dog> newItems = createThreeDogs();
items.clear();
items.addAll(newItems);
} );

Silverlight XAML binding is throwing Null Reference Exception

My qusetion is in continuation with previous post I have my combo box placed within other child grid, named "grid_SortPart". So, I have tried to set GetUIElement("grid_SortPart").DataContext = _viewModel; which somehow didn't work for me.
I have also tried changing _target.Loaded to _target.LayoutUpdated, but still same problem exists. During debugging I found that, I am getting error "Object reference not set to an instance of an object." for object _target.
Following is my code I setted up by referring post.Please suggest me the thing which I did wrong along with the way to correct it out.
public ObservableCollection<ReturnStatus> _status;
[TestInitialize]
public void TestInit()
{
_target = new EfileView();
efvm = new EfileViewModel();
var p1 = new ReturnStatus { Status = "Completed" };
var p2 = new ReturnStatus { Status = "Not Completed" };
_status = new ObservableCollection<ReturnStatus> { p1, p2 };
GetUIElement<Grid>("grid_SortPart").DataContext = efvm;
}
private T GetUIElement<T>(string name) where T : UIElement
{ return (T)_target.FindName(name); }
[Asynchronous]
[TestMethod]
public void TestCurrencySelection()
{
_target.LayoutUpdated += (s, e) =>
{
// Set the currency list explicitly
efvm.ItemSource_ReturnStatus = _status;
var currencyCombo = GetUIElement<ComboBox>("cmb_Returns_2");
// This assert fails as Items.Count == 0
CollectionAssert.AreEquivalent(currencyCombo.Items, _status, "Failed to data-bind currencies.");
EnqueueTestComplete();
};
TestPanel.Children.Add(_target);
}

Resources