Silverlight - привязка свойства IsEnabled для кнопки к свойству в модели представления - PullRequest
3 голосов
/ 22 февраля 2010

Я создаю приложение Silverlight и хочу отключить кнопку, когда в фоновом режиме выполняется длительная операция. Я использую MVVM, поэтому в ViewModel у меня есть свойство с именем SearchInProgress. Теперь я хотел бы отключить кнопку поиска всякий раз, когда SearchInProgress в true. В WPF я просто написал бы DataTrigger, который устанавливает IsEnabled для кнопки поиска в false.

К сожалению, DataTriggers не доступны в Silverlight, поэтому я ищу другое решение. Я пытался играть с VisualStateManager, но я нигде не получил. VSM кажется излишним из-за этой простой вещи, которую я пытаюсь достичь.

Любая помощь приветствуется.

Ответы [ 8 ]

7 голосов
/ 23 февраля 2010

Вместо того, чтобы прыгать через обручи, чтобы установить SearchInProgress=true, установите IsEnabled=false, почему бы просто не создать свойство CanSearch и связать его с ним. Свойство может быть доступно только для чтения (или иметь собственный установщик), а другое свойство может инициировать событие PropertyChanged от его имени.

В конечном счете, цель модели представления состоит в том, что вы удаляете логику из представления. Привязка представления к SearchInProgress (и, следовательно, использование преобразователя для его отрицания для IsEnabled) подразумевает, что представление понимает , когда оно должно или не должно иметь возможность поиска. Однако привязка к свойству CanSearch означает, что модель представления полностью контролирует, когда поиск включен, и представление может оставаться немым.

Кроме того, вы можете использовать API-интерфейсы поведения Blend, установленные вместе с Blend, поскольку они имеют что-то похожее на триггеры данных.

1 голос
/ 22 февраля 2010

Возможно, лучший способ - использовать DelegateCommand из Prism2, прикрепив его к кнопке поиска и реализовав его метод CanExecute в ViewModel, чтобы он возвращал! SearchInProgress.

Затем, когда ViewModel инициирует операцию поиска, он изменит SearchInProgress на true (так что CanExecute возвращает false), а затем вызовет RaiseCanExecuteChanged для команды (что приведет к отключению кнопки), как только операция поиска закончится над ViewModel изменит SearchInProgress обратно на false (чтобы CanExecute вернул true), а затем снова вызовет RaiseCanExecuteChanged (что приведет к включению кнопки)

0 голосов
/ 13 сентября 2011

Вам нужно создать команду и привязать ее к кнопке. Все, что вы ищете, запекается для вас во время выполнения. Такие фреймворки, как MVVM Light и Prism, позволяют легко создавать новые команды, но вы можете сделать это самостоятельно, например:

Создайте класс, который реализует ICommand. Дайте ему приватное имя по имени SearchInProgress. Когда поиск начнется, установите для SearchInProgress значение true. Когда поиск завершится (либо успешно, либо по причине истечения времени ожидания, был прерван и т. Д.), Установите для SearchInProgress значение false. Реализация ICommand.CanExecute возвращает! SearchInProgress. Предоставьте Search ICommand для вашей модели представления, а затем привяжите свойство команды кнопки к команде на вашей модели представления.

псевдопользователей-код:

public class MySearchCommand : ICommand
{
  public event EventHandler CanExecuteChanged;
  private bool _searching;
  private bool SearchInProgress
  {
    get { return _searching; }
    set
    {
      if (_searching == value) return;
      _searching = value;
      if (CanExecuteChanged != null) CanExecuteChanged(this, EventArgs.Empty);
    }

  public bool CanExecute(object param)
  {  return !SearchInProgress }

  public void Execute(object param)
  {
    try
    {
      SearchInProgress = true;
      // search code here including callback to OnSearchCompleted method
    }
    catch(Exception ex)
    {
      SearchInProgress = false;
    }
  }

  private void OnSearchCompleted(SomeCallbackResult result)
  {
    SearchInProgress = false;
  }
}

public class ViewModel : INotifyPropertyChange
{
  public ICommand SearchCommand { get; private set; }
  public ViewModel()
  {
    SearchCommand = new MySearchCommand();
  }
}

XAML:

<UserControl ....>
  <UserControl.DataContext>
    <ViewModel />
  </UserControl.DataContext>
  <Grid>
    <Button Command={Binding SearchCommand} />
  </Grid>
</UserControl>
0 голосов
/ 24 февраля 2010

Я нашел решение, которое меня вполне устраивает. Сначала я определил два состояния VSM в своей сетке LayoutRoot 'SearchInProgress' и 'Normal'.

        <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="Standard">
            <VisualState x:Name="SearchInProgress">
                <Storyboard>
                    <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="SearchButton" Storyboard.TargetProperty="(Control.IsEnabled)">
                        <DiscreteObjectKeyFrame KeyTime="00:00:00">
                            <DiscreteObjectKeyFrame.Value>
                                <system:Boolean>False</system:Boolean>
                            </DiscreteObjectKeyFrame.Value>
                        </DiscreteObjectKeyFrame>
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="SearchCancelButton" Storyboard.TargetProperty="(Control.IsEnabled)">
                        <DiscreteObjectKeyFrame KeyTime="00:00:00">
                            <DiscreteObjectKeyFrame.Value>
                                <system:Boolean>True</system:Boolean>
                            </DiscreteObjectKeyFrame.Value>
                        </DiscreteObjectKeyFrame>
                    </ObjectAnimationUsingKeyFrames>
                </Storyboard>
            </VisualState>
            <VisualState x:Name="Normal"/>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

Довольно упрощенно, и я мог бы адаптировать их, но это работает.

Для переключения между состояниями я использую DataStateBehavior из здесь , что позволяет мне привязать свойство к текстовому тексту (viewmodel) и соответственно переключаться между двумя состояниями:

        <interactivity:Interaction.Behaviors>
        <exprsamples:DataStateBehavior Binding="{Binding Path=SearchIsInProgress, Mode=TwoWay}"
                                       Value="True"
                                       TrueState="SearchInProgress"
                                       FalseState="Normal">
        </exprsamples:DataStateBehavior>
    </interactivity:Interaction.Behaviors>

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

0 голосов
/ 24 февраля 2010

Для этого нет абсолютно никакой причины добавлять DLL PRISM в ваш проект. Вам нужно всего 10 строк кода и 2 модульных теста.

Вы все еще хотите использовать командный шаблон, хотя. Добавьте присоединенное свойство «Command», которое принимает «ICommand», и когда свойство установлено, вы:

  1. Соблюдайте команду и включите или отключите кнопку, когда она запрашивает.
  2. Добавляет обработчик к событию «Щелчок» кнопки, который вызывает метод «Выполнить» для команды.

Примечание о ПРИЗМЕ: Библиотека отстой! Но Руководство по составным приложениям является незаменимым пособием для любого, кто пишет приложение MVVM, и предоставляет дополнительную информацию о шаблоне команд.

0 голосов
/ 23 февраля 2010

Единственное разумное решение, о котором я могу подумать в данный момент, - это иметь событие "SearchCompleted" в ViewModel, на которое подписывается представление, а затем соответствующим образом меняет представление при возникновении события.

0 голосов
/ 22 февраля 2010

Привязать к свойству SearchInProgress, но запустить его через конвертер, чтобы обратить логическое значение.

В Связке, что-то вроде

IsEnabled="{Binding Path=SearchInProgress,Converter={StaticResource YOURCONVERTERHERE}}"

В функции конвертера конвертер, я думаю, это будет

return !(value as bool)

С любыми проверками работоспособности, которые вы хотите поставить для проверки на нулевые предметы и т. Д.

0 голосов
/ 22 февраля 2010

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

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