Условный DataTrigger для динамического изменения включенного состояния кнопки в WPF UserControl - PullRequest
0 голосов
/ 21 ноября 2010

Я создал UserControl для использования в качестве навигатора данных.Я определил два свойства DependencyProperties в этом элементе управления следующим образом (подразумевается DependencyProperty):

public ICollection DataCollection
{
    get { return GetValue(DataCollectionProperty) as ICollection; }
    set { SetValue(DataCollectionProperty, value); }
}

public ICollectionView View
{
    get { return (DataCollection == null ? null : CollectionViewSource.GetDefaultView(DataCollection)); }
}

Затем я поместил четыре кнопки для выполнения основных операций навигации (первая, предыдущая, следующая, последняя).Каждая кнопка получает следующий стиль:

<Style x:Key="NavButtonStyle" TargetType="{x:Type Button}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding DataCollection}" Value="{x:Null}">
            <Setter Property="IsEnabled" Value="False" />
        </DataTrigger>
    </Style.Triggers>
</Style>

Все, что делает этот триггер, это проверяет, является ли DataCollection DependencyProperty нулевым, при условии, что RelativeResource TemplatedParent передается как DataContext каждой кнопки, например:

<Button (...) DataContext="{RelativeSource TemplatedParent}">

Затем я создал следующее MarkupExtension для сравнения значений и возврата true или false, основываясь на операции сравнения и сравниваемых значениях:

[MarkupExtensionReturnType(typeof(bool))]
public class ComparisonBinding : BindingDecoratorBase
{
    public ComparisonOperation Operation { get; set; }
    public object Comparand { get; set; }

    public override object ProvideValue(IServiceProvider provider)
    {
        base.ProvideValue(provider);

        DependencyObject targetObject;
        DependencyProperty targetProperty;
        bool status = TryGetTargetItems(provider, out targetObject, out targetProperty);

        if (status && Comparand != null)
        {
            if (Comparand is MarkupExtension)
                Comparand = (Comparand as MarkupExtension).ProvideValue(provider);
            return Compare(targetObject.GetValue(targetProperty), Comparand, Operation);
        }

        return false;
    }

    private static bool Compare(object source, object target, ComparisonOperation op)
}

Наконец, я использовал этот ME для проверки «Включения».«условия для каждой кнопки.Вот условие для кнопки Первая :

<Button (...) DataContext="{RelativeSource TemplatedParent}"
    IsEnabled="{DynamicResource {mark:ComparisonBinding Path=View.CurrentPosition, RelativeSource={RelativeSource TemplatedParent}, Comparand={Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataCollection.Count}, Operation=EQ}}">

К сожалению, это решение не сработало.Я продолжаю получать это исключение времени разработки:

InvalidOperationException: Невозможно получить NodePath для ViewNode, который не является частью дерева представления.

У кого-нибудь есть лучшее решение?Может быть, я пытаюсь убить муху с помощью пушки здесь.:)

Заранее спасибо.Эдуардо Мело

1 Ответ

0 голосов
/ 21 ноября 2010

На мой взгляд, лучший способ реализовать включенную / отключенную функциональность для кнопок - это использовать интерфейс ICommand и метод CanExecute.Для этой цели вы можете использовать облегченную реализацию, такую ​​как DelegateCommand в Prism или RelayCommand в MVVMLight, и если вы действительно хотите добиться максимальной эффективности, не регистрируйте команды с помощью CommandManager - вместо этого запускайте CanExecuteChanged при определенных условиях, которые должны быть доступны в коде.

На практике это означает, что ваш пользовательский элемент управления будет содержать (или сам будет) своего рода микро-ViewModel (с экземплярами ICommand и реализацией для их методов Execute и CanExecute), что является наилучшим способом переходаВ любом случае разработка WPF.В этом случае все, что вам нужно в XAML - это привязать свойство Command кнопок к соответствующей ICommand.Это также позволит безошибочно предоставлять команды (которые могут рассматриваться как «задачи» с функциональной точки зрения) любым другим вызывающим сторонам, включая модульные тесты, если вы так склонны.

Совершенно законно, что ICommands выставляютсянапример, ваш элемент управления и кнопки внутри шаблона элемента управления, привязанные к тем же командам (используя RelativeSource Self);вы даже можете связать их видимость с другим свойством (UseBuiltInButtons), и если позже вы захотите интегрировать свой элемент управления с каким-нибудь необычным интерфейсом, вы можете просто скрыть кнопки и связать внешние с теми же ICommands.

LetЯ знаю, если это помогает или просто сбивает с толку, и я постараюсь пролить больше света на этот вопрос!Конечно, это всего лишь идея, и могут быть и другие, не менее хорошие.

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