2016-05-19 1 views
-2

Я пытаюсь настроить группу радиостанций, которая контролирует, какую команду выполняет одна кнопка, и хотел бы, чтобы радиогруппа вернулась к опции по умолчанию (первая) после выполнения любой другой функции. Я знаю, что могу сделать это в моей модели просмотра, привязывая значения группы радио к свойству и затем используя это свойство в модели представления. Но тогда у меня будет одна команда, которая проверяет, что свойство отправляется соответствующему обработчику внутри модели представления, хотя концептуально действительно существует несколько команд.Раскадровка запускается слишком рано или сброса переключателей с экрана?

Я предпочел бы сохранить модель представления семантически точной, то есть разоблачить отдельные команды и дать представление понять, как выполнить соответствующий. Например, может быть какая-то альтернативная реализация представления, которая фактически показывает пользователю разные кнопки для каждой команды или даже запускает команды другим способом. В этом случае я бы не хотел, чтобы представление реализовало прокси-сервер, чтобы он мог установить свойство выбора команды модели представления перед выполнением фактической команды. Я хочу, чтобы модель представления отображала эти команды как отдельные команды.

Но мне трудно понять, как привязать кнопку «Выполнить» непосредственно к соответствующей команде модели представления и по-прежнему автоматически отменить выбор группы переключателей по умолчанию, как только пользователь нажал кнопку «Выполнить».

Я думал, что смогу активировать Storyboard, когда кнопка нажата, в котором по умолчанию RadioButton повторно проверяется (т.е. IsChecked установлен в true). Это почти срабатывает, но в первый раз, когда нажата кнопка, кажется, что Storyboard завершает мгновенно один раз, перед выполнением команды, а затем снова запускается. Это заставляет выполнить команду по умолчанию, а не выбранную пользователем (если не по умолчанию); по-видимому, состояние переключателя сбрасывается до того, как кнопка «Execute» фактически выполняет команду, и поэтому она выполняет неправильную команду.

Вот мой простой пример того, что я имею в виду:

ViewModel.cs

class ViewModel 
{ 
    public ICommand A { get; private set; } 
    public ICommand B { get; private set; } 

    public ViewModel() 
    { 
     A = new Command("A"); 
     B = new Command("B"); 
    } 

    class Command : ICommand 
    { 
     private readonly string _text; 

     public Command(string text) 
     { 
      _text = text; 
     } 

     public bool CanExecute(object parameter) 
     { 
      return true; 
     } 

     public event EventHandler CanExecuteChanged; 

     public void Execute(object parameter) 
     { 
      MessageBox.Show("Executed " + _text); 
     } 
    } 

} 

XAML:

<Window x:Class="TestSOAskResetRadioButton.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:l="clr-namespace:TestSOAskResetRadioButton" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.DataContext> 
    <l:ViewModel/> 
    </Window.DataContext> 

    <StackPanel> 
    <StackPanel Orientation="Horizontal"> 
     <RadioButton x:Name="buttonA" Content="A" IsChecked="True"/> 
     <RadioButton x:Name="buttonB" Content="B"/> 
    </StackPanel> 
    <Button Content="Execute" HorizontalAlignment="Left"> 
     <Button.Style> 
     <Style TargetType="Button"> 
      <Setter Property="Command" Value="{Binding A}"/> 
      <Style.Triggers> 
      <DataTrigger Binding="{Binding IsChecked, ElementName=buttonB}" Value="True"> 
       <Setter Property="Command" Value="{Binding B}"/> 
      </DataTrigger> 
      <EventTrigger RoutedEvent="Click"> 
       <BeginStoryboard> 
       <Storyboard Storyboard.Target="{x:Reference Name=buttonA}" 
          Storyboard.TargetProperty="IsChecked" BeginTime="0:0:5"> 
        <BooleanAnimationUsingKeyFrames Duration="0"> 
        <DiscreteBooleanKeyFrame KeyTime="0" Value="True"/> 
        </BooleanAnimationUsingKeyFrames> 
       </Storyboard> 
       </BeginStoryboard> 
      </EventTrigger> 
      </Style.Triggers> 
     </Style> 
     </Button.Style> 
    </Button> 
    </StackPanel> 
</Window> 

Я установил BeginTime свойство для Storyboard в 5 секунд, чтобы преувеличивать поведение, которое я вижу, поэтому более очевидным. Независимо от значения BeginTime, при первом нажатии кнопки «Выполнить» по умолчанию переключатель по умолчанию сразу же выбирается, и в любое последующее время, когда нажимается кнопка, все работает нормально (даже если BeginTime равно 0).

Чтобы воспроизвести проблему, просто запустите программу, нажмите переключатель «B», а затем нажмите кнопку «Выполнить». Радиокамера «А» будет немедленно выбрана, и команда «А» будет выполнена.

После того, как «Выполнить» кнопка была нажата один раз, если вы ждете значения BeginTime истечь, а затем повторите попытку — т.е. выбрать переключатель «B» и нажмите кнопку «Выполнить» кнопки — она отлично работает (сразу повторное выделение кнопки «В» после первой попытки позволяет легко увидеть, когда истек BeginTime, поскольку анимация фактически сбросит выбор на кнопку «А» в этот момент времени).

В принципе: она появляется, как будто первый раз он работает, то Storyboard сразу устанавливает целевое свойство конечного значения, а затем выполняется до завершения, установив его снова. При каждом последующем запуске он оставляет целевое свойство только до тех пор, пока кнопка «Выполнить» не сможет выполнить привязанную команду, установив свойство target только один раз.

Как мне избежать преждевременного возврата переключателя в выбранное состояние?


Если есть лучший способ, не связанный с моделью просмотра, для просмотра, чтобы сбросить состояние переключателя после выполнения команды, это также будет прекрасный ответ. Я считаю, что использовать Storyboard таким образом немного взломан, по меньшей мере; «анимировать» что-то просто, чтобы я мог переключить значение обратно в исходное состояние, похоже, излишне. Просто я не знаю другого способа приблизиться к этому, все еще сдерживая логику взгляда.

Добавление: я понял, после размещения вопрос о том, что классический запасной вариант/хак для отсроченного действия с помощью Dispatcher.InvokeAsync() будет работать в этом случае. Я могу обработать событие Button.Click, и в обработчике этот метод используется для вызова оператора, который устанавливает свойство IsChecked. Это немного сложно, потому что в моем реальном сценарии эти элементы фактически объявлены в DataTemplate, поэтому мне нужно позвонить FrameworkElement.FindName(), чтобы получить RadioButton Мне нужно установить обратно на отмеченный (вместо, например, с помощью имени поля, созданного XAML для объекта). Но это работает нормально.

Я бы по-прежнему очень хотел ответить, объясняя поведение Storyboard, особенно если есть что-то в этом роде, что я делаю неправильно, и, конечно, любые другие разумные действия будут приветствоваться (особенно если они лучше, чем тот, который у меня уже есть).

+0

Ваша команда также является обязательной и может прыгать так же, как любая другая привязка. Я предлагаю добавить все команды в ViewModel, а затем применить свойство, подобное «SelectedCommand», которое является самой ICommand. Затем привяжите кнопку к ней. Вы можете легко переключить команды на кнопку таким образом. –

ответ

1

В этом примере радиокнопки выбирают новую команду, а нажатие кнопки выполняет новую команду. После выполнения команды возвращается команда по умолчанию.

Это ViewModel, который имеет разные команды и свойство для выбранной команды.

public class MultiCommandViewModel : INotifyPropertyChanged 
{ 
    private object value; 
    private ICommand selectedCommand; 

    public MultiCommandViewModel() 
    { 
     SetValueToXCommand = new RelayCommand((obj) => setValue(obj), (obj) => true); 
     SetValueToNameCommand = new RelayCommand((obj) => setValue("Michael"), (obj) => true); 
     SetValueTo1000Command = new RelayCommand((obj) => setValue(1000), (obj) => true); 
     SetSelectedCommand = new RelayCommand((obj) => SelectedCommand = obj as ICommand, (obj) => true); 
    } 

    private void setValue(object obj) 
    { 
     Value = obj; 
     SelectedCommand = null; 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    public void Notify([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 

    public object Value 
    { 
     get { return value; } 
     set 
     { 
      this.value = value; 
      Notify(); 
     } 
    } 

    public ICommand SelectedCommand 
    { 
     get { return (selectedCommand == null) ? SetValueToNameCommand : selectedCommand; } 
     set 
     { 
      selectedCommand = value; 
      Notify(); 
     } 
    } 

    public RelayCommand SetValueToXCommand { get; private set; } 
    public RelayCommand SetValueToNameCommand { get; private set; } 
    public RelayCommand SetValueTo1000Command { get; private set; } 
    public RelayCommand SetSelectedCommand { get; private set; } 
} 

Вот View (нет коды позади или триггера/раскадровка)

<UserControl.DataContext> 
    <ViewModels:MultiCommandViewModel /> 
</UserControl.DataContext> 

<StackPanel> 

    <RadioButton Content="Set to Name Command" 
       GroupName="selectCommand" 
       Command="{Binding SetSelectedCommand}" 
       CommandParameter="{Binding SetValueToNameCommand}" 
       Margin="12" 
       IsChecked="True"/> 

    <RadioButton Content="Set to 1000 Command" 
       GroupName="selectCommand" 
       Command="{Binding SetSelectedCommand}" 
       CommandParameter="{Binding SetValueTo1000Command}" 
       Margin="12" /> 

    <RadioButton Content="Set to (X) Command" 
       GroupName="selectCommand" 
       Command="{Binding SetSelectedCommand}" 
       CommandParameter="{Binding SetValueToXCommand}" 
       Margin="12" /> 

    <StackPanel Margin="12"> 
     <TextBlock Text="Enter X Value" /> 
     <TextBox Name="TextBoxValue" 
       Text="Dummy Value" /> 
    </StackPanel> 

    <Button Content="Execute Selected Command" 
      Command="{Binding SelectedCommand}" 
      CommandParameter="{Binding Text, ElementName=TextBoxValue}" 
      Margin="12" /> 

    <StackPanel Margin="12"> 
     <TextBlock Text="Value" /> 
     <TextBlock Text="{Binding Value}" /> 
    </StackPanel> 

</StackPanel> 

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

Start Up

При нажатии на кнопку ...

Button Click

Выбор «Установите (X) Command, изменив значение 'Hello World' и нажмите на кнопку.

Button Click after changing command selection

и так далее ...

Смежные вопросы