Я столкнулся с той же проблемой, будь то не с ToggleButton
, а с TextBox
, где я хотел отформатировать текст, который пользователь ввел.
В вашем случае вы хотите изменить свойство IsChecked
в своей модели просмотра и сразу же отобразить его в пользовательском интерфейсе (так что всегда не снимайте флажок). Причина, по которой вы этого хотите, абсолютно не имеет значения.
Проблема в том, что с UWP получатель получает ваше имя, как вы ожидаете, когда вы нажимаете ToggleButton
. Обычным действием для ToggleButton
является изменение с непроверенного на проверенное (и наоборот), и это то, что происходит в вашем случае. Но тогда вы ожидаете, что NotifyPropetyChanged
сигнализирует управление в пользовательском интерфейсе. И тут все пошло не так. Геттер никогда не вызывается при запуске сеттера (включая NotifyPropertyChanged
), поэтому пользовательский интерфейс не отражает то, что вы сделали в своем сеттере. Это сильно отличается от того, что делало TwoWay Binding (и все еще делает это в WPF). Таким образом, в вашем коде нет ничего плохого, но кажется, что механизм привязки изменился, хотя Microsoft утверждает, что это не так. Если вы используете x:Bind
, он отлично работает, поэтому шляпа может решить вашу проблему.
Чтобы прояснить ситуацию, я привел ваш пример и немного изменил его, чтобы показать проблему. Я поставил ToggleButton
на странице с привязкой TwoWay к viewmodel, точно так же, как вы. Нажатие на ToggleButton
переключит свое состояние с отмеченного на непроверенное и наоборот, хотя установщик в моей модели просмотра всегда устанавливает для свойства значение false (поэтому не установлен). Но я также добавил обычную кнопку, которую я привязал к команде, которая также изменяет свойство, к которому привязан ToggleButton
. Нажатие этой кнопки вызывает установщика в свойстве, к которому привязан ToggleButton
. Конечно, сеттер вызывает одно и то же, но после этого вызывается привязка к ToggleButton
, поэтому NotifyPropertyChanged
в этом случае вызывает обновление пользовательского интерфейса.
Если вы используете отладчик, вы можете точно видеть, что я имею в виду. Итак, ваша проблема может быть решена с помощью x: Bind или путем выяснения другого способа обновления пользовательского интерфейса, который вам не нужно делать, если Binding все еще работает так, как раньше. Возможно, Microsoft реализовала какую-то оптимизацию, которая теперь уничтожает классическое Binding.
Никаких особых вещей, просто MainPage и viewmodel.
Мой код MainPage.xaml
<Page x:Class="App10.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:App10"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<local:ViewModel x:Key="viewModel" />
</Page.Resources>
<Grid x:Name="mainGrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Margin="10,20,10,0">
<Button
x:Name="Button"
Content="UWP Normal button"
Command="{Binding Source={StaticResource viewModel}, Path=SwitchIschecked}"
HorizontalAlignment="Stretch" />
<ToggleButton
x:Name="toggleButton"
Margin="0,10,0,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
IsChecked="{Binding Source={StaticResource viewModel}, Path=IsChecked,
Mode=TwoWay}">
<TextBlock>UWP Toggle Button</TextBlock>
</ToggleButton>
</StackPanel>
</Grid>
</Page>
Код для MainPage.xaml.cs
using Windows.UI.Xaml.Controls;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace App10
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
}
}
И код для ViewModel.cs
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
namespace App10
{
public class ViewModel : INotifyPropertyChanged
{
private bool _isChecked;
// property for TwoWay binding with ToggleButton
public bool IsChecked
{
get
{
return _isChecked;
}
set
{
// extra var just to check 'value'
var _value = value;
// now always set it to false
_isChecked = false;
// Try to pass value of _isChecked to user interface
// because there is no check whether the value really
// has changed
// But this only works if the setter is not being called
// directly from the control the property is bound to
OnPropertyChanged();
}
}
private ICommand _switchChecked;
// ICommand for normal button, binding to Command
// calls method to set Property for ToggleButton
public ICommand SwitchIschecked
{
get
{
if (_switchChecked == null)
_switchChecked = new ChangeChecked(new Action(ChangeVar));
return _switchChecked;
}
set
{
_switchChecked = value;
}
}
// This will set the property for the ToggleButton
private void ChangeVar()
{
IsChecked = !IsChecked;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
/// <summary>
/// Quick class to implement ICommand
/// </summary>
class ChangeChecked : ICommand
{
Action _execute;
public ChangeChecked(Action execute)
{
_execute = execute;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_execute();
}
}
}
попробовать сделать класс 'ModelView 'public class – thumbmunkeys
Создание класса ClassView в общедоступном классе по-прежнему не является обязательным.:/ ToggleButton все равно переключится на «Проверено». – user3863376
ваш 'set' делает' _isEnabled = false; '.... – jsanalytics