WPF为多个类创建通用“选择器工具”

时间:2009-06-16 17:17:49

标签: wpf list

如果将它减少到一个类,问题就很容易了。给定下面的图像,我想创建一个简单的双面控件,根据布尔值将一个列表中的项放入另一个列表中。

编辑:您当然可以点击两个列表中的项目,然后该项目切换到另一个列表。此外,如果我需要更新某些数据库内容,则会调用回调...

我创造了一幅漂亮的照片,让你有点动摇,因为我被卡住了......

世界并不像示例那么简单:您如何为各种类别解决这个问题。

想象一下像“IsFast”这样的“Car”这样的课程。或者像“ILikeIt”这样的“水果”这样的课程。我不想每次重新编程WPF控件,我需要一些方法来绑定...(哦,我想我只是有个想法)......但是,是否有任何好的做法如何允许泛型类(如T)只要它们实现某些属性..或者是一个包装类?

我不知道,你怎么解决它。与OnClick函数的简单绑定似乎还不够......不确定......顺便说一句,“编写3个控件”是一个合适的答案。如果它更简单,请告诉我。

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

3 个答案:

答案 0 :(得分:1)

怎么做?

  • 创建一个名为PickList的控件,其子类ItemsControl包含用于挑选单个项目,挑选所有项目,取消所有项目等的命令
  • 创建一个名为PickListItem的类,其中包含IsPicked属性
  • 定义PickList的控件模板,以包含两个ListBox es和一组按钮,用于选择一个,所有等等。该模板将包含一些CollectionViewSource个用于将那些被挑选的项目(将在右侧)与那些未被采用的项目(将在左侧)隔离。

然后您可以像使用任何其他ItemsControl一样使用此控件,并将其重用于您可能拥有的任何数据类型:

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

答案 1 :(得分:1)

认为我明白你的意思,这应该让你开始。

我假设你的usercontrol有两个listview,一个用于名为“TrueList”的 true 项,另一个用于名为“FalseList”的 false 项。< / p>

从ItemsCollection扩展您的usercontrol,并将每个listview的ItemsSource属性绑定到父usercontrol的ItemsSource。

TrueFilter FalseFilter 属性添加到您的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;
        }
    }

然后创建一个“IToggle”(或其他更有意义的名称)界面:

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

然后,为每个自定义类扩展ObservableCollection,实现“IToggle”界面:

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;
    }

接下来,覆盖用户控件上的ItemsSource属性:

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;
   }
}

最后,在事件回调中调用TrueList.Items.Refresh()和FalseList.Items.Refresh(),以便在将项目从true切换为false时刷新项目视图,反之亦然。

这个解决方案仍然需要为每个自定义类(真假过滤器)编写一些实现代码,但它应该将额外的代码保持在最低限度。

或者,如果您为每个自定义类提供一个通用接口,它将是一个更简单的解决方案,如:

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

然后,您可以使用一组过滤器(或样式设置器,或使用转换器进行数据绑定)来对抗“有效”接口。而不是“Car.IsFast”和“Fruit.ILikeIt”,你会使用“Car.IsValid”和“Fruit.IsValid”。

答案 2 :(得分:0)

制作用户控件。添加SourceList dep。属性。为回调添加委托属性,为“is in list”过滤器添加委托属性

使用两个ListBox控件(左侧和右侧),使用CollectionViewSource设置两个列表的来源,使用过滤器委托来确定成员资格。