Extended WPF Toolkit - CheckComboBox - wpf

Is anyone aware of a way to manually enable (turning on the tick) on the Check Boxes within the CheckComboBox for WPFToolkit?
Unfortunately, the Items in the Combo-box are all strings.
I'm trying to enable all flags when "Select All" checkbox is ticked.

This is a rather late response but I thought it best to post this in case it helps someone out. I have used the following approach for the WPFToolkit version:
public class Descriptor : INotifyPropertyChanged
{
private bool isSelected;
public bool IsSelected
{
get
{
return this.isSelected;
}
set
{
if (this.isSelected != value)
{
this.isSelected = value;
// Raise INotifyPropertyChanged
}
}
}
public string Name { get; set; }
}
Create a collection of these and then assign them to the ItemsSource of the CheckComboBox.
To handle select all we have an option labelled: "" as the first item in the collection, then if this item is ticked all the items are de-selected and the all case is handle under the hood. To handle the selection Changed it does involve adding an event to the Descriptor class and firing it each time the IsSelected property is changed.

I eventually tossed out Extended WPFToolkit due to it's inability to access the checkboxes directly.
Instead I created a ComboBox and manually defined Checkboxes within it, which I access directly by name, and there able to implement a "Select All" by using it's [Checked/Unchecked[ event, and use the ComboBox SelectionChanged to show a default value that expresses what has been selected in a CSV format.
Maybe be clunky, but it gets the job done.
PS. I did not need to even bother with a DataTemplate for the ComboBox

One way in the code Behind is
var ComboSelector = MyCheckComboBox as Xceed.Wpf.Toolkit.Primitives.Selector;
foreach(var item in MyCheckComboBox.Items)
ComboSelector.SelectedItems.Add(item);

Related

Setting observable object to NULL == CRASH

I have a List bound to a (Telerik) GridView. The selected item is a separate variable of type T which is assigned the object of the selected row in the GridView when the user clicks on a row. T is derived from ObservableObject. This means I am using MVVM Light Toolkit.
I need to deselect the row from my ViewModel in certain situations. On the GridView control this works, if the selected item is set to NULL in the ViewModel. Whenever I do this, MVVM reports a crash (NPE). I debugged it and saw that it is failing in ObservableObject.cs. It calls a method
protected bool Set<T>(
Expression<Func<T>> propertyExpression,
ref T field,
T newValue)
and crashes one line before return when calling RaisePropertyChanged(propertyExpression)
I don't know if this is working as designed or not. My problem is, that I need to set the selected Object to NULL in the ViewModel to deselect a row of my GridView in the View. I CANNOT use CodeBehind for the deselection!
Code I have:
public ObservableCollection<ContractTypeDto> ContractTypes { get; private set; }
public ContractTypeDto SelectedContractType
{
get { return _selectedContractType; }
set
{
Set(() => SelectedContractType, ref _selectedContractType, value);
RaisePropertyChanged(() => SelectedContractType);
}
}
When you click on a row in the grid it opens a new UserControl containing lots of details of this record. This control has its own ViewModel. I store the calling view Model (where the selected item is stored). When the page (control) is closed (destroyed) I have to deselect the row in the grid. I call a method like so:
protected void DeselectCallersSelectedItem()
{
if (CallingObject == typeof(ContractTypeListViewModel))
{
var vm = SimpleIoc.Default.GetInstance<ContractTypeListViewModel>();
vm.SelectedContractType = null;
}
}
Any ideas?
To remove the collection you can either set the SelectedItem property to null or clear the SelectedItems.
gridViewName.SelectedItem = null;
gridViewName.SelectedItems.Clear();
Without showing the code, we cannot precisely help you. A solution I think you can do is to implement the INotifyPropertyChanged interface in your view model and bind the selected item to a property of that type. Also check the output window if there is any binding failure.

WPF databinding: how is detected an item change?

I have some issue with WPF databinding, and I hope to be clear in my explaination because I fear that the problem is very subtle.
I have essentially a WPF UserControl with a bunch of ComboBox, each one is chained to each other. I mean that the first combobox is filled with some elements, and when the user select and item, the second combobox is filled with elements based on the previous selection, and so on with other combox.
All combobox are binded with UpdateSourceTrigger=LostFocus.
The code for a ItemsSource property of a combo looks like this:
private ICollectionView allTicketTypesView;
public IEnumerable<TicketTypeBase> AllTicketTypes
{
get { return this.allTicketTypesView.SourceCollection.Cast<TicketTypeBase>(); }
private set
{
IEnumerable<TicketTypeBase> enumerable = value ?? new TicketTypeBase[0];
ObservableCollection<TicketTypeBase> source = new ObservableCollection<TicketTypeBase>(enumerable);
this.allTicketTypesView = CollectionViewSource.GetDefaultView(source);
this.OnPropertyChanged("AllTicketTypes");
}
}
The code for a SelectedItem property of a combo is similar to this code:
private TicketTypeBase ticketType;
public TicketTypeBase TicketType
{
get { return this.ticketType; }
set
{
this.ticketType = value;
this.OnPropertyChanged("TicketType");
this.UpdateConcessions();
}
}
I'm experiencing a subtle problem:
when i move with keyboard and/or mouse over my combo, I see that often propertychanged is called also when I actually don't change any of the items of the list.
I mean that a combo is filled with elements, and an item is selected: moving over the combo with the keyboard trigger the propertychanged (and let the other combo to be updated, that is an indesidered behavior), but the element itself is the same.
I see this behavior in a combobox that is binded with a list of strings (so I suppose no error on Equals/GetHashCode implementation) and this behavior happens everytime except the first time.
I've fixed the code with this:
private string category;
public string Category
{
get { return this.category; }
set
{
bool actuallyChanged = !String.Equals(this.category, value);
this.category = value;
this.OnPropertyChanged("Category");
if (!actuallyChanged)
{
string format = String.Format("Category '{0}' isn't changed actually", value);
Trace.WriteLine(format);
}
else this.UpdateTicketTypes():
}
}
But of course I don't like this code that add logic to the setters.
Any suggestion about how to avoid this behavior?
I hope to be clear, and I'm ready to explain better my problem if someone don't understand clearly.
It is not unreasonable for your model to check whether a value used in a property setter is actually different from the current value. However a more 'standard' implementation would look like the following:
private string category;
public string Category
{
get { return this.category; }
set
{
// check this is a new value
if(Object.Equals(this.category, value))
return;
// set the value
this.category = value;
// raise change notification
this.OnPropertyChanged("Category");
// compute related changes
this.UpdateTicketTypes():
}
}
Just a guess but can you implement SelectedValue binding instead of SelectedItem? SelectedValue (for value types like int, string, bool etc.) do no refresh upon keyboard or mouse focuses and even when ItemsSource (with CollectionView) changes coz the change notifications in the source (or model) not fire as value types do not change by reference.

MVVM and (dynamically) filling a combobox from the value of another combobox

I have a form with two ComboBoxes. One of them is being filled with objects coming from a collection in the ViewModel. When I select a value in this ComboBox, it then should fill the second ComboBox.
What I want to know is what the best way is to go about filling the second ComboBox. I think having yet another collection with the details of the selected value of the first ComboBox in the ViewModel might be a bit wasteful. I think the best way might be to hit the database with the selected value, collecting the corresponding details, and then send them back. How I think this would work is to have the details ComboBox have a binding with the 'master' ComboBox so it can get the selected value. Then ideally, the details ComboBox would then somehow get the values from the database.
Problem is that I just don't know how to implement this with MVVM, and any help would be appreciated!
Just call OnPropertyChanged of the details collection once the selected item changes.
You can pre-populate a background dictionary whose key is the possible master items and whose values are a list of detail list.
Note for the below to work you ViewModel must implement INotifyPropertyChanged
e.g.
public class MyViewModel : INotifyPropertyChanged
{
public IEnumerable<MasterOption> MasterList {get;set;}
public IEnumerable<DetailOption> DetailList {get;set;}
Dictionary<MasterOption,List<DetailOption>> DetailLookup;
MasterOption _SelectedMasterOption;
public MasterOption SelectedMasterOption
{
get { return _SelectedMasterOption;}
set
{
_SelectedMasterOption = value;
LoadDetailsList();
OnPropertyChanged("SelectedMasterOption");
}
void LoadDetailsList()
{
InitDictionary();
if (DetailLookup.ContainsKey(SelectedMasterOption))
DetailList = DetailLookup[SelectedMasterOption];
else
DetailList = null;
OnPropertyChanged("DetailList");
}
void InitDictionary()
{
if (DetailLookup == null)
{
//Grab fill the lookup dictionary with information
}
}
}
Create a method in your ViewModel that gets the data for the second combobox and update with BindingExpression in your codebehind.
private void FirstComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
_viewModel.SelectionChange();
BindingExpression bindingExpression = BindingOperations.GetBindingExpression(SecondComboBox, ComboBox.ItemsSourceProperty);
bindingExpression.UpdateTarget();
}

Silverlight: how to bind List<T> to data grid

MVVM pattern is implemented in my Silverlight4 application.
Originally, I worked with ObservableCollection of objects in my ViewModel:
public class SquadViewModel : ViewModelBase<ISquadModel>
{
public SquadViewModel(...) : base(...)
{
SquadPlayers = new ObservableCollection<SquadPlayerViewModel>();
...
_model.DataReceivedEvent += _model_DataReceivedEvent;
_model.RequestData(...);
}
private void _model_DataReceivedEvent(ObservableCollection<TeamPlayerData> allReadyPlayers, ...)
{
foreach (TeamPlayerData tpd in allReadyPlayers)
{
SquadPlayerViewModel sp = new SquadPlayerViewModel(...);
SquadPlayers.Add(sp);
}
}
...
}
Here is a peacie of XAML code for grid displaying:
xmlns:DataControls="clr-namespace:System.Windows.Controls;
assembly=System.Windows.Controls.Data"
...
<DataControls:DataGrid ItemsSource="{Binding SquadPlayers}">
...</DataControls:DataGrid>
and my ViewModel is bound to DataContext property of the view.
This collection (SquadPlayers) is not changed after its creation so I would like to change its type to
List<SquadPlayerViewModel>
. When I did that, I also added
RaisePropertyChanged("SquadPlayers")
in the end of '_model_DataReceivedEvent' method (to notify the grid that list data are changed.
The problem is that on initial displaying grid doesn't show any record... Only when I click on any column header it will do 'sorting' and display all items from the list...
Question1: Why datagrid doesn't contain items initially?
Q2: How to make them displayed automatically?
Thanks.
P.S. Here is a declaration of the new List object in my view-model:
public List<SquadPlayerViewModel> SquadPlayers { get; set; }
You can't use List as a binding source, because List not implement INotifyCollectionChanged it is require for WPF/Silverlight to have knowledge for whether the content of collection is change or not. WPF/Sivlerlight than can take further action.
I don't know why you need List<> on your view model, but If for abstraction reason you can use IList<> instead. but make sure you put instance of ObservableCollection<> on it, not the List<>. No matter what Type you used in your ViewModel Binding Only care about runtime type.
so your code should like this:
//Your declaration
public IList<SquadPlayerViewModel> SquadPlayers { get; set; }
//in your implementation for WPF/Silverlight you should do
SquadPlayers = new ObservableCollection<SquadPlayerViewModel>();
//but for other reason (for non WPF binding) you can do
SquadPlayers = new List<SquadPlayerViewModel>();
I usually used this approach to abstract my "Proxied" Domain Model that returned by NHibernate.
You'll need to have your SquadPlayers List defined something like this:
private ObservableCollection<SquadPlayerViewModel> _SquadPlayers;
public ObservableCollection<SquadPlayerViewModel> SquadPlayers
{
get
{
return _SquadPlayers;
}
set
{
if (_SquadPlayers== value)
{
return;
}
_SquadPlayers= value;
// Update bindings, no broadcast
RaisePropertyChanged("SquadPlayers");
}
}
The problem is that whilst the PropertyChanged event informs the binding of a "change" the value hasn't actually changed, the collection object is still the same object. Some controls save themselves some percieved unnecessary work if they believe the value hasn't really changed.
Try creating a new instance of the ObservableCollection and assigning to the property. In that case the currently assigned object will differ from the new one you create when data is available.

'EditItem' is not allowed for this view - databinding issue

I am trying to do data binding in WPF on a data grid using a custom list. My custom list class contains a private data list of type List<T>. I cannot expose this list, however the indexers are exposed for setting and getting individual items.
My custom class looks like this:
public abstract class TestElementList<T> : IEnumerable
where T : class
{
protected List<T> Data { get; set; }
public virtual T Get(int index)
{
T item = Data[index];
return item;
}
public virtual void Set(int index, T item)
{
Data[index] = item;
}
...
}
The data is binded but when I try to edit it, I get 'EditItem' is not allowed for this view error. On doing extensive searching over web, I found that I might need to implement IEditableCollectionView interface also.
Can anybody please help me to either give pointers on how to implement this interface or any suggest any other better way to do databinding on custom list?
Though I am not fully understanding your requirement, do you think using an ObservableCollection will solve your issue?
public abstract class TestElementList<T> : ObservableCollection<T>
where T : class
{
public virtual T Get(int index)
{
T item = this[index];
return item;
}
public virtual void Set(int index, T item)
{
this[index] = item;
}
...
}
I had the same exception. It seems that you have to bind do IList. I was binding to a IEnumerable and this exception was thrown.
Just to add my own observation. I had a datagrid with specifically defined columns in Xaml and its ItemsSource set to a simple dictionary. When I tried to edit the second column, I got this exception referring to the dictionary. I then set the data grid ItemsSource to a list of the Keys (dataGrid.Keys.ToList()). I could then edit the second column. It seems a list view allows an 'EditItem'.
edit: Did a little bit more digging into this. I set up a BeginningEdit handler and started poking around. One thing I noticed was that every single time I got this error, EditingEventArgs.Source was a Border. If I can find the time, I may look into this one down a bit further. Also, on one instance, my converting the dictionary keys to a List did not work. I had to convert it to an Observable collection, despite the fact that a List was suitable in all other places in my code where I was doing essentially an identical type of assignment.
edit again: Ok, I have another fix for those for which using an IList type doesn't work. Attach a BeginningEdit handler to your DataGrid and point to this code:
private void Grid_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
{
//// Have to do this in the unusual case where the border of the cell gets selected
//// and causes a crash 'EditItem is not allowed'
e.Cancel = true;
}
This will only hit if you somehow manage to physically tap down on the border of the cell. The event's OriginalSource is a Border, and I think what my happen here is instead of a TextBox, or other editable element being the source as expected, this un-editable Border comes through for editing, which causes an exception that is buried in the 'EditItem is not allowed' exception. Canceling this RoutedEvent before it can bubble on through with its invalid Original Source stops that error occurring in its tracks.
Glad to have found this as there was, in my case, a DataGrid on which I couldn't use an IList type.

Resources