MVVM: привязка радио кнопок к модели представления? - PullRequest
59 голосов
/ 18 февраля 2010

РЕДАКТИРОВАТЬ: Проблема была исправлена ​​в .NET 4.0.

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

Вот мой вопрос: существует ли простой и надежный способ привязки переключателей с помощью MVVM? Спасибо.

Дополнительная информация: Свойство IsChecked не работает по двум причинам:

  1. Когда кнопка выбрана, свойства IsChecked других кнопок в группе не устанавливаются на false .

  2. Когда кнопка выбрана, ее собственное свойство IsChecked не устанавливается после первого нажатия кнопки. Я предполагаю, что WPF с первого клика перехватывает привязку.

Демонстрационный проект: Вот код и разметка для простого демо, воспроизводящего проблему. Создайте проект WPF и замените разметку в Window1.xaml на следующую:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300" Loaded="Window_Loaded">
    <StackPanel>
        <RadioButton Content="Button A" IsChecked="{Binding Path=ButtonAIsChecked, Mode=TwoWay}" />
        <RadioButton Content="Button B" IsChecked="{Binding Path=ButtonBIsChecked, Mode=TwoWay}" />
    </StackPanel>
</Window>

Замените код в Window1.xaml.cs на следующий код (взлом), который устанавливает модель представления:

using System.Windows;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            this.DataContext = new Window1ViewModel();
        }
    }
}

Теперь добавьте следующий код в проект как Window1ViewModel.cs:

using System.Windows;

namespace WpfApplication1
{
    public class Window1ViewModel
    {
        private bool p_ButtonAIsChecked;

        /// <summary>
        /// Summary
        /// </summary>
        public bool ButtonAIsChecked
        {
            get { return p_ButtonAIsChecked; }
            set
            {
                p_ButtonAIsChecked = value;
                MessageBox.Show(string.Format("Button A is checked: {0}", value));
            }
        }

        private bool p_ButtonBIsChecked;

        /// <summary>
        /// Summary
        /// </summary>
        public bool ButtonBIsChecked
        {
            get { return p_ButtonBIsChecked; }
            set
            {
                p_ButtonBIsChecked = value;
                MessageBox.Show(string.Format("Button B is checked: {0}", value));
            }
        }

    }
}

Чтобы воспроизвести проблему, запустите приложение и нажмите кнопку A. Появится окно сообщения о том, что для свойства кнопки IsChecked установлено значение true . Теперь выберите кнопку B. Появится еще одно окно с сообщением о том, что для свойства IsChecked для кнопки B установлено значение true , но нет сообщения о том, что для свойства IsChecked для кнопки A установлено значение false - свойство не было изменено.

Теперь нажмите кнопку A еще раз. Кнопка будет выбрана в окне, но окно сообщения не появится - свойство IsChecked не было изменено. Наконец, нажмите кнопку B еще раз - тот же результат. Свойство IsChecked вообще не обновляется ни для одной кнопки после первого нажатия кнопки.

Ответы [ 11 ]

0 голосов
/ 24 октября 2016

У меня очень похожая проблема в VS2015 и .NET 4.5.1

XAML:

                <ListView.ItemsPanel>
                    <ItemsPanelTemplate>
                        <UniformGrid Columns="6" Rows="1"/>
                    </ItemsPanelTemplate>
                </ListView.ItemsPanel>
                <ListView.ItemTemplate>
                    <DataTemplate >
                        <RadioButton  GroupName="callGroup" Style="{StaticResource itemListViewToggle}" Click="calls_ItemClick" Margin="1" IsChecked="{Binding Path=Selected,Mode=TwoWay}" Unchecked="callGroup_Checked"  Checked="callGroup_Checked">

....

Как вы можете видеть в этом коде, у меня есть просмотр списка, а элементы в шаблоне - это радиокнопки, принадлежащие имени группы.

Если я добавлю новый элемент в коллекцию со свойством Selected, установленным в True, он будет отмечен, а остальные кнопки останутся отмеченными.

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

код:

`....
  lstInCallList.ItemsSource = ContactCallList
  AddHandler ContactCallList.CollectionChanged, AddressOf collectionInCall_change
.....
Public Sub collectionInCall_change(sender As Object, e As NotifyCollectionChangedEventArgs)
    'Whenever collection change we must test if there is no selection and autoselect first.   
    If e.Action = NotifyCollectionChangedAction.Add Then
        'The solution is this, but this shouldn't be necessary
        'Dim seleccionado As RadioButton = getCheckedRB(lstInCallList)
        'If seleccionado IsNot Nothing Then
        '    seleccionado.IsChecked = False
        'End If
        DirectCast(e.NewItems(0), PhoneCall).Selected = True
.....
End sub

`

...