WPF Create a Common Pick Tool for Multiple Classes

the problem is quite simple if you reduce it to one class. Given the following image, I want to create a simple two-way control that puts items from one list to another depending on a boolean value.

EDIT: You can, of course, click the items in both lists, and the item will switch to another list. In addition, a callback is called in case I need to update some database files ...

I created a nice picture to move you a little, because I'm stuck ...

The world is not as simple as an example: How would you solve this for different classes.

Imagine a class like Car with IsFast. Or a class like Fruits with ILikeIt. I don’t want to reprogram the WPF control every time, I need to somehow bind ... (oh, I think I got an idea) ... but still is there any good practice on how to allow common classes (e.g. T) as long as they realize certain properties. Or a wrapper class?

I have no idea how you would solve this. Simply linking to OnClick functions seems insufficient ... Not sure ... And, by the way, “ write 3 controls” is the right answer . If it's easier, just tell me.

alt text http://img31.imageshack.us/img31/96/listexample.png

+4
source share
3 answers

I think I understand what you need, this should start.

I assume that your usercontrol has two lists intended for true elements named "TrueList" and the other for false elements named "FalseList".

Extend your usercontrol from the ItemsCollection and bind the ItemsSource property of each list to the ItemsSource of the parent usercontrol.

Add the TrueFilter and 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 the “IToggle” interface (or another more meaningful name):

 public interface IToggle { Predicate<object> TrueFilter { get; } Predicate<object> FalseFilter { get; } } 

Then continue with the 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; } 

Then override the ItemsSource property of 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 () in your event callbacks to update the element views each time the element switches from true to false and vice versa.

This solution still requires writing implementation code for each custom class (true and false filters), but it should contain minimal code.

Alternatively, this would be much simpler if you provided each of your user classes with a common interface, for example:

 public interface Valid { bool IsValid { get; set; } } 

Then you can use one set of filters (or style installers or data binding to converters) to work with the "Valid" interface. Instead of Car.IsFast and Fruit.ILikeIt, you will use Car.IsValid and Fruit.IsValid.

+1
source

How can I do it?

  • Create a PickList control that subclasses ItemsControl and includes commands to select one item, select all items, delete all items, etc.
  • Create a class called PickListItem that has the IsPicked property
  • Define a control pattern for PickList to include two ListBox es and a bunch of buttons to select one, all, and so on. The template should include a CollectionViewSource pair to separate those elements that are selected (which will be on the right) from those that are not (which will be on the left).

You will then use this control, like any other ItemsControl , and reuse it for any data type that you may have:

 <PickList ItemsSource="{Binding People}"> <PickList.ItemContainerStyle> <Style TargetType="{x:Type PickListItem}"> <Setter Property="IsPicked" Value="{Binding IsRich}"/> </Style> </PickList.ItemContainerStyle> </PickList> 
+1
source

make a custom control. add the SourceList parameter. Property. Add a delegate property for your callback, add a delegate property for the "is in list" filter

use two ListBox controls (left and right), use CollectionViewSource to set the source of two lists, using a filter delegate to determine membership.

0
source

Source: https://habr.com/ru/post/1286309/


All Articles