WPF Создать универсальный «инструмент выбора» для нескольких классов - PullRequest
4 голосов
/ 16 июня 2009

проблема довольно проста, если вы уменьшите ее до одного класса. Учитывая следующее изображение, я хочу создать простой двусторонний элемент управления, который помещает элементы из одного списка в другой в зависимости от логического значения.

РЕДАКТИРОВАТЬ: Конечно, вы можете нажать на элементы в обоих списках, и элемент переключается на другой список. Кроме того, вызывается обратный вызов, на случай, если мне нужно обновить некоторые вещи БД ...

Я создал красивую картинку, чтобы немного оживить вас, потому что я застрял ...

Мир не так прост, как в примере: Как бы вы решили это для различных классов.

Представьте себе класс типа "Автомобиль" с "IsFast". Или класс как "Фрукты" с "ILikeIt". Я не хочу перепрограммировать элемент управления WPF каждый раз, мне нужен какой-то способ привязки ... (о, я думаю, что я только что понял) ... но все же, есть ли хорошая практика, как разрешать универсальные классы (например, T) до тех пор, пока они реализуют определенные свойства. Или класс-оболочка?

Понятия не имею, как бы вы решили это. Простого связывания с функциями OnClick кажется недостаточно ... Не уверен ... И, кстати, " write 3 control" - это подходящий ответ . Если это проще, просто скажи мне.

альтернативный текст http://img31.imageshack.us/img31/96/listexample.png

Ответы [ 3 ]

1 голос
/ 16 июня 2009

Как бы Я это сделал?

  • Создайте элемент управления с именем 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 голос
/ 16 июня 2009

Я думаю Я понимаю, что вы после этого, это должно начать вас.

Я предполагаю, что ваш usercontrol имеет два списка просмотра, один из которых предназначен для true элементов с именем "TrueList", другой для false элементов с именем "FalseList".

Расширьте свой usercontrol из ItemsCollection и свяжите свойство ItemsSource каждого просмотра списка с ItemsSource родительского usercontrol.

Добавьте свойство TrueFilter и FalseFilter в свой пользовательский контроль:

   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, и наоборот.

Это решение все еще требует написания некоторого кода реализации для каждого пользовательского класса (фильтры true и false), но оно должно сводить дополнительный код к минимуму.

В качестве альтернативы было бы гораздо более простое решение, если бы вы дали каждому из ваших пользовательских классов общий интерфейс, что-то вроде:

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

Тогда вы могли бы использовать один набор фильтров (или наборы стилей, или привязку данных с конвертерами) для работы с «Действительным» интерфейсом. Вместо «Car.IsFast» и «Fruit.ILikeIt» вы должны использовать «Car.IsValid» и «Fruit.IsValid».

0 голосов
/ 16 июня 2009

сделать пользовательский контроль. добавить SourceList dep. Имущество. Добавьте свойство делегата для обратного вызова, добавьте свойство делегата для фильтра «в списке»

используйте два элемента управления ListBox (слева и справа), используйте CollectionViewSource , чтобы установить источник двух списков, используя делегат фильтра для определения членства.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...