I want To know if there is a way to Define how many times a Grid can bind to a list ?
for example , If I have a list of 20 elements , can I restrict the Binding To just the First Ten elements of the list .
the problem is that I use the same list for 2 different controls , I need the first control to bind to the entire all list , and the second to bind to the first 10 elements . so is there is anyway to do this from XAML ?
thanks :))
On your code-behind, or view-model, or wherever said list is, just set a property that exposes what you want:
public IEnumerable<something> MyTopElements
{
get { return myList.Take(10); }
}
and bind to that instead
in that case
public List<something> MyTopItems
{
get { return myItems.Take(10); }
}
public List<something> MyItems
{
get { return myItems; }
}
Related
I have a custom ComboBox in WinForms that is supposed to display an enumeration. Basically, I derived from ComboBox and in the constructor, I load the items from the enum.
The problem is that, even though at the end of the process it says the count of items is the same as the enum item count, the visual representation shows as if the same items were added twice. In other words, if my enum had values Value1 and Value2 the ComboBox says it has two values but when dropping down it shows Value1, Value2, Value1, Value2 as if I had added them twice.
public class EnumComboBox : ComboBox
{
public EnumComboBox() : base()
{
foreach (MyEnum p in Enum.GetValues(typeof(MyEnum)) {
base.Items.Add(p);
}
SelectedIndex = 0;
}
}
As you can see in the code, in the constructor the items are added ONCE but they are listed twice. What am I doing wrong here?
Rather than in the Constructor the manner to get it to behave properly was to leave the constructor empty and move the insertion code to the OnCreate method:
protected override void OnCreateControl()
{
if (!DesignMode) {
foreach (MyEnum p in Enum.GetValues(typeof(MyEnum))) {
Items.Add(p);
}
SelectedIndex = 0;
}
}
I have Model like this
interface IStudent {
string Name;
List<Subjects> Marks;
int RollNumber;
}
class ViewModel {
ObservableCollection<IStudent> FromExcel;
ObservableCollection<IStudent> FromDB;
}
I need to bind the union of both collection on UI. Whats the best way. I was thinking of having another property ObservableCollection<IStudent> FromBoth; generated using LINQ Union method with comparer. My question is
Is it fine to have three collection to bind on UI? Note: I need to remove duplicates, giving priority to data from excel.
I need to pick some data from DB rather than excel in certain case.
For example: name="hungrymind" in fromExcel and name="hungrymind concepts" on fromDB collection. By default, grid on UI should show hungrymind (priority to excel), but if user uncheck column(aka property) from UI, then priority to data for that column becomes DB, i.e, UI should show "hungrymind concepts"
What should be approach to achieve this. My approach would be on user event, pick data from FromDB or FromExcel for each items in the collection and assign it to property in FromBoth collection. Since there are more than 100 columns, I had to use reflection, but wouldn't be slow down the performance? If I avoid reflection, then I have to write a method for each column. Any suggestion on pattern or approach ?
I solved the issue like this
interface IStudent {
string Name { get; set; }
List<Subjects> Marks { get; set; }
int RollNumber { get; set; }
}
class EntityViewModel: IStudent {
IStudent FromExcel;
IStudent FromDB;
public string Name {
get { return Choose("Name").Name; }
set { Choose("Name").Name = value; }
}
public string RollNumber{
get { return Choose("RollNumber").RollNumber; }
set { Choose("RollNumber").RollNumber = value; }
}
internal IStudent Choose(string propertyName){
if(IsOveridable(propertyName))
return this.FromExcel;
else
return this.FromDB
}
}
class ViewModel{
ObservableCollection<EntityViewModel> Entities;
}
In that case why don't you build a meta-model which would help you in organizing the data, like for instance
String objectName
String dataType
String defaultName
String displayName
String userSelectedName
boolean isUserOvverride
String viewType // (i.e. Text Input, Combo Box, Text Area, Radio Button, Multi Line List)
String viewElementTypeId // (i.e. for Combo Box,Radio Button this refers to user options available and for Text Input or Area it would be null)
Though the above approach decreases the performance but you can adopt to any number of types that might come in tomorrow.
I have a bool array of size 4 and I want to bind each cell to a different control.
This bool array represents 4 statuses (false = failure, true = success).
This bool array is a propery with a class:
class foo : INotifyPropertyChanged {
...
private bool[] _Statuses;
public bool[] Statuses
{
get {return Statuses;}
set {
Statuses = value;
OnPropertyChanged("Statuses");
}
}
In XAML there are 4 controls, each one bound to one cell of the array:
... Text="{Binding Path=Statuses[0]}" ...
... Text="{Binding Path=Statuses[1]}" ...
... Text="{Binding Path=Statuses[2]}" ...
... Text="{Binding Path=Statuses[3]}" ...
The problem is that the notify event is raised only when I change the array itself and isn't raised when I change one value within the array, i.e, next code line raises the event:
Statuses = new bool[4];
but next line does not raises the event:
Statuses [0] = true;
How can I raise the event each time one cell is changed?
You need to expose your statuses as an indexer, then raise a property change event that indicates that the indexer has changed.
private bool[] _Statuses;
public bool this[int index]
{
get { return _Statuses[index]; }
set
{
_Statuses[index] = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(Binding.IndexerName));
}
}
See this blog post:
http://10rem.net/blog/2010/03/08/wpf---silverlight-quick-tip-inotifypropertychanged-for-indexer
It doesn't raise the event becuase Array itself doesn't implement INotifyPropertyChanged. You can either use a different container than the primitive array (anything that implements INotifyCollectionChanged liked ObservableCollection<T> should do) OR you have to call RaisePropertyChanged("Statuses") each time you update the Statuses array OR, as metioned in another answer, use one class that implement INotifyPropertyChanged that contains 4 properties.
You cannot do it while using an Array. Changing a value at any index on an Array does not raise change notification required by the UI.
Can you use a class with four properties that implements INotifyPropertyChanged interface instead?
In a datagrid I have two DataGridComboBoxColumns. The items of one of these columns should depend on what is selected in the other column. The underlying collection used to model this is a dictionary<string,List<string>>. How should i go about implementing this? I can't seem to hook up to any relevant events on the columns, and I cant find any databinding scenarios that support this..
I had the same scenario a while back and fixed it like this:
public class DataItem : INotifyPropertyChanged {
...
public List<SomeObject> DisplayableComboBoxItems {
get; set;
}
private static Dictionary<int, List<SomeObject>> myDict;
public Dictionary<int, List<SomeObject>> MyDict {
get {
if (myDict == null) {
myDict = GetYourDataFromSomewhere();
}
return myDict;
}
}
public int TypeId {
get { return typeId; }
set {
if (value == typeId) return;
typeId = value;
RaisePropertyChanged("TypeId");
}
}
public int TypeSetId {
get { return typeSetId; }
set {
if (typeSetId == value) return;
typeSetId = value;
RaisePropertyChanged("TypeSetId");
DisplayableComboBoxItems = MyDict[typeSetId];
RaisePropertyChanged("DisplayableComboBoxItems");
TypeId = 0;
}
}
...
}
DataItem is the object that gets bound to a DataRow.
This is just a small mock-up of the code. Basically, whenever the TypeSet changes, I needed a new list of Types to be displayed. I used just a static list, in this example i used a dictionary.
With this setup you can bind you combobox ItemsSource to the 'DisplayableComboBoxItems', and your SelectedValue to "TypeId".
You're gonna need other properties to display the correct text instead of the TypeId.
The downside of this is that when you have 1000+ items, you'll have that same list for all items. This wasn't however the case with me (DataGrid showed max 50 items).
I hope this is clear enough and that it helps you in the right direction!
cheers!
Roel
Instead of using a DataGridComboBoxColumn for the second column, I went with a DataGridTemplateColumn with an embedded Combobox. For the itemsource i defined a converter: string -> List<string>. The converter translates the value of the selecteditem of the other DataGridComboBox (which is bound to Navn) into List<string>, this is just a dictionary lookup.
Like so:
<my:DataGridTemplateColumn>
<my:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox SelectedItem="{Binding Værdi}"
ItemsSource="{Binding Navn, Converter={StaticResource dimensionToValues}}"
>
</ComboBox>
</DataTemplate>
</my:DataGridTemplateColumn.CellTemplate>
</my:DataGridTemplateColumn>
the problem is pretty easy if you reduce it to one class. Given the following image, I want to create a simple two sided control, which puts items from one list into the other depending on a boolean value.
EDIT: You can of course click on items in both lists, and the item switches to the other list. Also, a callback is called, in case I need to update some DB stuff...
I created a nice picture to movivate you a little bit, because I am stuck...
The world is not so simple like the example: How would you solve this for various classes.
Imagine a class like "Car" with "IsFast". Or a class like "Fruits" with "ILikeIt". I do not want to reprogramm the WPF control each time, I need some way to bind... (oh, I think I just got an idea)... but still, is there any good practice how to allow generic classes (like T) as long as they implement certain properties.. Or a wrapper class?
I have no idea, how would you solve it. Simple binding with OnClick Functions seems not enough... Not sure... And, by the way, "write 3 controls" IS a suitable answer. If it is simpler, just tell me.
alt text http://img31.imageshack.us/img31/96/listexample.png
I think I understand what you are after, this should get you started.
I am assuming that your usercontrol has two listviews, one intended for the true items named "TrueList", the other for the false items named "FalseList".
Extend your usercontrol from ItemsCollection and bind the ItemsSource property of each listview to the ItemsSource of the parent usercontrol.
Add a TrueFilter and a FalseFilter property to your usercontrol:
Predicate<object> trueFilter;
public Predicate<object> TrueFilter
{
get
{
return trueFilter;
}
set
{
if (trueFilter!= null && this.TrueList.Items != null)
this.TrueList.Items.Filter -= trueFilter;
trueFilter = value;
if (trueFilter!= null && this.TrueList.Items != null)
this.TrueList.Items.Filter += trueFilter;
}
}
Predicate<object> falseFilter;
public Predicate<object> FalseFilter
{
get
{
return falseFilter;
}
set
{
if (falseFilter!= null && this.FalseList.Items != null)
this.FalseList.Items.Filter -= falseFilter;
filter = value;
if (falseFilter!= null && this.FalseList.Items != null)
this.FalseList.Items.Filter += falseFilter;
}
}
Then create an "IToggle" (or some other more meaningful name) interface:
public interface IToggle
{
Predicate<object> TrueFilter { get; }
Predicate<object> FalseFilter { get; }
}
Then, extend ObservableCollection for each of your custom classes, implementing the "IToggle" interface:
public class Cars : ObservableCollection<Car>, IToggle
{
Predicate<object> trueFilter;
public Predicate<object> TrueFilter
{
get
{
if (trueFilter == null)
trueFilter = new Predicate<object>(this.TrueFilterPredicate);
return trueFilter;
}
}
private bool TrueFilterPredicate(object value)
{
Car car = (Car)value;
return car.IsFast;
}
Predicate<object> falseFilter;
public Predicate<object> FalseFilter
{
get
{
if (falseFilter == null)
falseFilter = new Predicate<object>(this.FalseFilterPredicate);
return falseFilter;
}
}
private bool FalseFilterPredicate(object value)
{
Car car = (Car)value;
return !car.IsFast;
}
Next, override the ItemsSource property on your user control:
public new IEnumerable ItemsSource
{
get { return base.ItemsSource; }
set
{
if (value != null && !(value is IToggle))
throw new Exception("You may only bind this control to collections that implement IToggle.");
base.ItemsSource = value;
this.TrueFilter = base.ItemsSource == null ? null : (base.ItemsSource as IToggle).TrueFilter;
this.FalseFilter = base.ItemsSource == null ? null : (base.ItemsSource as IToggle).FalseFilter;
}
}
Finally, call TrueList.Items.Refresh() and FalseList.Items.Refresh() on your event callbacks to refresh the item views whenever you switch an item from true to false, and vice versa.
This solution still requires writing some implementation code for each custom class (the true and false filters), but it should keep the extra code to a minimum.
Alternatively, it would be a much simpler solution if you gave each of your custom classes a common interface, something like:
public interface Valid
{
bool IsValid { get; set; }
}
Then you could use a single set of filters (or style setters, or databinding with converters) to work against the "Valid" interface. Instead of "Car.IsFast" and "Fruit.ILikeIt" you would use "Car.IsValid" and "Fruit.IsValid".
How would I do it?
Create a control called PickList that subclasses ItemsControl and includes commands for picking a single item, picking all items, unpicking all items etcetera
Create a class called PickListItem that has an IsPicked property
Define the control template for PickList to include two ListBoxes and a bunch of buttons for picking one, all etcetera. The template would include a couple of CollectionViewSources to segregate those items that are picked (which would be on the right) from those that are not (which would be on the left)
You would then use this control just like any other ItemsControl, and reuse it for any data type you might have:
<PickList ItemsSource="{Binding People}">
<PickList.ItemContainerStyle>
<Style TargetType="{x:Type PickListItem}">
<Setter Property="IsPicked" Value="{Binding IsRich}"/>
</Style>
</PickList.ItemContainerStyle>
</PickList>
make a user control. add a SourceList dep. Property. Add a delegate property for your callback, add a delegate property for your "is in list" filter
use two ListBox controls ( a left and a right ), use CollectionViewSource to set the source of the two lists, using the filter delegate to determine membership.