Я пытаюсь настроить группу радиостанций, которая контролирует, какую команду выполняет одна кнопка, и хотел бы, чтобы радиогруппа вернулась к опции по умолчанию (первая) после выполнения любой другой функции. Я знаю, что могу сделать это в моей модели просмотра, привязывая значения группы радио к свойству и затем используя это свойство в модели представления. Но тогда у меня будет одна команда, которая проверяет, что свойство отправляется соответствующему обработчику внутри модели представления, хотя концептуально действительно существует несколько команд.Раскадровка запускается слишком рано или сброса переключателей с экрана?
Я предпочел бы сохранить модель представления семантически точной, то есть разоблачить отдельные команды и дать представление понять, как выполнить соответствующий. Например, может быть какая-то альтернативная реализация представления, которая фактически показывает пользователю разные кнопки для каждой команды или даже запускает команды другим способом. В этом случае я бы не хотел, чтобы представление реализовало прокси-сервер, чтобы он мог установить свойство выбора команды модели представления перед выполнением фактической команды. Я хочу, чтобы модель представления отображала эти команды как отдельные команды.
Но мне трудно понять, как привязать кнопку «Выполнить» непосредственно к соответствующей команде модели представления и по-прежнему автоматически отменить выбор группы переключателей по умолчанию, как только пользователь нажал кнопку «Выполнить».
Я думал, что смогу активировать 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
, особенно если есть что-то в этом роде, что я делаю неправильно, и, конечно, любые другие разумные действия будут приветствоваться (особенно если они лучше, чем тот, который у меня уже есть).
Ваша команда также является обязательной и может прыгать так же, как любая другая привязка. Я предлагаю добавить все команды в ViewModel, а затем применить свойство, подобное «SelectedCommand», которое является самой ICommand. Затем привяжите кнопку к ней. Вы можете легко переключить команды на кнопку таким образом. –