wake-up-neo.com

MVVM: Optionsfelder an ein Ansichtsmodell binden?

EDIT: Problem wurde in .NET 4.0 behoben.

Ich habe versucht, eine Gruppe von Optionsfeldern mit der IsChecked-Schaltfläche an ein Ansichtsmodell zu binden. Nachdem Sie andere Beiträge überprüft haben, scheint die IsChecked-Eigenschaft einfach nicht zu funktionieren. Ich habe eine kurze Demo zusammengestellt, die das Problem reproduziert, das ich unten aufgeführt habe.

Hier ist meine Frage: Gibt es eine unkomplizierte und zuverlässige Möglichkeit, Optionsfelder mit MVVM zu binden? Vielen Dank.

Zusätzliche Informationen: Die IsChecked-Eigenschaft funktioniert aus zwei Gründen nicht:

  1. Wenn eine Schaltfläche ausgewählt ist, werden die IsChecked-Eigenschaften der anderen Schaltflächen in der Gruppe nicht auf false gesetzt.

  2. Wenn eine Schaltfläche ausgewählt ist, wird ihre eigene IsChecked-Eigenschaft nicht festgelegt, nachdem die Schaltfläche zum ersten Mal ausgewählt wurde. Ich vermute, dass die Bindung beim ersten Klick von WPF verschrottet wird.

Demo-Projekt: Hier ist der Code und das Markup für eine einfache Demo, die das Problem reproduziert. Erstellen Sie ein WPF-Projekt, und ersetzen Sie das Markup in Window1.xaml durch Folgendes:

<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>

Ersetzen Sie den Code in Window1.xaml.cs durch den folgenden Code (einen Hack), der das Ansichtsmodell festlegt:

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();
        }
    }
}

Fügen Sie dem Projekt nun folgenden Code als Window1ViewModel.cs hinzu:

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));
            }
        }

    }
}

Um das Problem zu reproduzieren, führen Sie die App aus und klicken Sie auf Schaltfläche A. Ein Meldungsfeld wird angezeigt, in dem Sie darüber informiert werden, dass die Eigenschaft IsChecked von Button A auf true gesetzt wurde. Wählen Sie nun Button B aus. Ein weiteres Meldungsfeld zeigt an, dass die Eigenschaft IsChecked von Button B auf true gesetzt wurde. Es wird jedoch kein Meldungsfeld angezeigt, das darauf hinweist, dass die Eigenschaft IsChecked von Button A auf false gesetzt wurde. Die Immobilie wurde nicht geändert.

Klicken Sie nun erneut auf Button A. Die Schaltfläche wird im Fenster ausgewählt, aber es wird kein Meldungsfeld angezeigt. Die IsChecked-Eigenschaft wurde nicht geändert. Zum Schluss noch einmal auf Button B klicken - das gleiche Ergebnis. Die IsChecked-Eigenschaft wird für beide Schaltflächen nach dem ersten Klicken nicht aktualisiert.

58
David Veeneman

Wenn Sie mit Jasons Vorschlag beginnen, wird das Problem zu einer einzelnen Auswahl aus einer Liste, die sich sehr gut in eine ListBox übersetzt. An diesem Punkt ist es trivial, ein ListBox-Steuerelement so zu gestalten, dass es als RadioButton-Liste angezeigt wird.

<ListBox ItemsSource="{Binding ...}" SelectedItem="{Binding ...}">
    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <RadioButton Content="{TemplateBinding Content}"
                                     IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected}"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>
52
John Bowen

Sieht aus, als hätten sie die Bindung an die IsChecked-Eigenschaft in .NET 4 behoben. Ein in VS2008 defektes Projekt funktioniert in VS2010.

17
RandomEngy

Zum Nutzen aller, die diese Frage in der Zukunft erforschen, ist die Lösung, die ich letztendlich implementiert habe. Sie baut auf John Bowens Antwort auf, die ich als beste Lösung für das Problem auswählte.

Zuerst habe ich einen Stil für ein transparentes Listenfeld erstellt, das Optionsfelder als Elemente enthält. Dann erstellte ich die Schaltflächen, um in das Listenfeld zu gelangen. Meine Schaltflächen sind fest eingestellt, anstatt in die App als Daten eingelesen zu werden. Daher habe ich sie hart in das Markup eingecodiert.

Ich verwende ein Enum mit dem Namen ListButtons im Ansichtsmodell, um die Schaltflächen im Listenfeld darzustellen, und ich benutze die Tag-Eigenschaft jeder Schaltfläche, um einen Zeichenfolgenwert des enum-Werts an diese Schaltfläche zu übergeben. Mit der ListBox.SelectedValuePath-Eigenschaft kann ich die Tag-Eigenschaft als Quelle für den ausgewählten Wert angeben, die ich mithilfe der SelectedValue-Eigenschaft an das Ansichtsmodell binde. Ich dachte, ich brauche einen Wertkonverter, um zwischen dem String und seinem Aufzählungswert zu konvertieren, aber die integrierten Konverter von WPF haben die Konvertierung problemlos erledigt.

Hier ist das komplette Markup für Window1.xaml :

<Window x:Class="RadioButtonMvvmDemo.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">

    <!-- Resources -->
    <Window.Resources>
        <Style x:Key="RadioButtonList" TargetType="{x:Type ListBox}">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="ItemContainerStyle">
                <Setter.Value>
                    <Style TargetType="{x:Type ListBoxItem}" >
                        <Setter Property="Margin" Value="5" />
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type ListBoxItem}">
                                    <Border BorderThickness="0" Background="Transparent">
                                        <RadioButton 
                                            Focusable="False"
                                            IsHitTestVisible="False"
                                            IsChecked="{TemplateBinding IsSelected}">
                                            <ContentPresenter />
                                        </RadioButton>
                                    </Border>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </Setter.Value>
            </Setter>
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBox}">
                        <Border BorderThickness="0" Padding="0" BorderBrush="Transparent" Background="Transparent" Name="Bd" SnapsToDevicePixels="True">
                            <ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

    <!-- Layout -->
    <Grid>
        <!-- Note that we use SelectedValue, instead of SelectedItem. This allows us 
        to specify the property to take the value from, using SelectedValuePath. -->

        <ListBox Style="{StaticResource RadioButtonList}" SelectedValuePath="Tag" SelectedValue="{Binding Path=SelectedButton}">
            <ListBoxItem Tag="ButtonA">Button A</ListBoxItem>
            <ListBoxItem Tag="ButtonB">Button B</ListBoxItem>
        </ListBox>
    </Grid>
</Window>

Das Ansichtsmodell hat eine einzige Eigenschaft, SelectedButton, die eine ListButtons-Enumeration verwendet, um anzuzeigen, welche Schaltfläche ausgewählt ist. Die Eigenschaft ruft ein Ereignis in der Basisklasse auf, die ich für Ansichtsmodelle verwende. Dadurch wird das Ereignis PropertyChanged ausgelöst:

namespace RadioButtonMvvmDemo
{
    public enum ListButtons {ButtonA, ButtonB}

    public class Window1ViewModel : ViewModelBase
    {
        private ListButtons p_SelectedButton;

        public Window1ViewModel()
        {
            SelectedButton = ListButtons.ButtonB;
        }

        /// <summary>
        /// The button selected by the user.
        /// </summary>
        public ListButtons SelectedButton
        {
            get { return p_SelectedButton; }

            set
            {
                p_SelectedButton = value;
                base.RaisePropertyChangedEvent("SelectedButton");
            }
        }

    }
} 

In meiner Produktionsanwendung ruft der Setter SelectedButton eine Serviceklassenmethode auf, die die erforderliche Aktion ausführt, wenn eine Schaltfläche ausgewählt wird.

Um dies zu vervollständigen, ist hier die Basisklasse:

using System.ComponentModel;

namespace RadioButtonMvvmDemo
{
    public abstract class ViewModelBase : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region Protected Methods

        /// <summary>
        /// Raises the PropertyChanged event.
        /// </summary>
        /// <param name="propertyName">The name of the changed property.</param>
        protected void RaisePropertyChangedEvent(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);
                PropertyChanged(this, e);
            }
        }

        #endregion
    }
}

Hoffentlich hilft das!

9
David Veeneman

Eine Lösung besteht darin, das ViewModel für die Optionsfelder im Setter der Eigenschaften zu aktualisieren. Wenn Button A auf True eingestellt ist, setzen Sie Button B auf False.

Ein weiterer wichtiger Faktor beim Binden an ein Objekt im DataContext ist, dass das Objekt INotifyPropertyChanged implementieren soll. Wenn sich eine gebundene Eigenschaft ändert, sollte das Ereignis ausgelöst werden und den Namen der geänderten Eigenschaft enthalten. (Nullprüfung wurde in der Stichprobe aus Gründen der Kürze weggelassen.)

public class ViewModel  : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected bool _ButtonAChecked = true;
    public bool ButtonAChecked
    {
        get { return _ButtonAChecked; }
        set 
        { 
            _ButtonAChecked = value;
            PropertyChanged(this, new PropertyChangedEventArgs("ButtonAChecked"));
            if (value) ButtonBChecked = false;
        }
    }

    protected bool _ButtonBChecked;
    public bool ButtonBChecked
    {
        get { return _ButtonBChecked; }
        set 
        { 
            _ButtonBChecked = value; 
            PropertyChanged(this, new PropertyChangedEventArgs("ButtonBChecked"));
            if (value) ButtonAChecked = false;
        }
    }
}

Bearbeiten:

Das Problem ist, dass sich der IsChecked-Wert beim ersten Klicken auf Button B ändert und die Bindung durchläuft, Button A jedoch nicht durch seinen ungeprüften Status an die ButtonAChecked-Eigenschaft übergeben wird. Durch manuelle Aktualisierung im Code wird der ButtonAChecked-Eigenschaftssetzer aufgerufen, wenn das nächste Mal auf Button A geklickt wird.

3
Doug Ferguson

Hier haben Sie eine andere Möglichkeit, dies zu tun 

AUSSICHT:

<StackPanel Margin="90,328,965,389" Orientation="Horizontal">
        <RadioButton Content="Mr" Command="{Binding TitleCommand, Mode=TwoWay}" CommandParameter="{Binding Content, RelativeSource={RelativeSource Mode=Self}, Mode=TwoWay}" GroupName="Title"/>
        <RadioButton Content="Mrs" Command="{Binding TitleCommand, Mode=TwoWay}" CommandParameter="{Binding Content, RelativeSource={RelativeSource Mode=Self}, Mode=TwoWay}" GroupName="Title"/>
        <RadioButton Content="Ms" Command="{Binding TitleCommand, Mode=TwoWay}" CommandParameter="{Binding Content, RelativeSource={RelativeSource Mode=Self}, Mode=TwoWay}" GroupName="Title"/>
        <RadioButton Content="Other" Command="{Binding TitleCommand, Mode=TwoWay}" CommandParameter="{Binding Content, RelativeSource={RelativeSource Mode=Self}}" GroupName="Title"/>
        <TextBlock Text="{Binding SelectedTitle, Mode=TwoWay}"/>
    </StackPanel>

ViewModel:

 private string selectedTitle;
    public string SelectedTitle
    {
        get { return selectedTitle; }
        set
        {
            SetProperty(ref selectedTitle, value);
        }
    }

    public RelayCommand TitleCommand
    {
        get
        {
            return new RelayCommand((p) =>
            {
                selectedTitle = (string)p;
            });
        }
    }
2
Enkosi

Bei IsChecked-Fehlern sind Sie nicht sicher, ein möglicher Refactor könnte Ihr Sichtmodell sein: Die Ansicht hat eine Reihe von sich gegenseitig ausschließenden Zuständen, die durch eine Reihe von RadioButtons dargestellt werden, von denen jeweils nur einer ausgewählt werden kann. Im Ansichtsmodell haben Sie nur eine Eigenschaft (z. B. eine Aufzählung), die die möglichen Zustände darstellt: stateA, stateB usw. Auf diese Weise würden Sie nicht alle einzelnen ButtonAIsChecked usw. benötigen 

2
Jason Roberts

Eine kleine Erweiterung von John Bowens answer : Es funktioniert nicht, wenn die Werte ToString() nicht implementieren. Was Sie brauchen, anstatt die Content des RadioButton auf eine TemplateBinding zu setzen, geben Sie einfach eine ContentPresenter so ein:

<ListBox ItemsSource="{Binding ...}" SelectedItem="{Binding ...}">
    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <RadioButton IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected}">
                            <ContentPresenter/>
                        </RadioButton>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

Auf diese Weise können Sie gegebenenfalls zusätzlich DisplayMemberPath oder ItemTemplate verwenden. Der RadioButton "umschließt" nur die Elemente und stellt die Auswahl bereit.

2

Ich weiß, dass dies eine alte Frage ist, und das ursprüngliche Problem wurde in .NET 4 gelöst. Um ehrlich zu sein, ist dies ein wenig abwegiges Thema. 

In den meisten Fällen, in denen ich RadioButtons in MVVM verwenden wollte, muss zwischen Elementen eines enum ausgewählt werden. Dazu muss an jeden Button und eine bool - Eigenschaft im VM Leerzeichen gebunden werden Wenn Sie eine allgemeine enum - Eigenschaft festlegen, die die tatsächliche Auswahl widerspiegelt, wird dies sehr schnell sehr langweilig. Daher habe ich eine Lösung entwickelt, die wiederverwendbar und sehr einfach zu implementieren ist und keine ValueConverter erfordert.

Die Ansicht ist ziemlich gleich, aber wenn Sie Ihr enum an Ort und Stelle haben, können Sie die VM Seite mit einer einzigen Eigenschaft erledigen.

MainWindowVM

using System.ComponentModel;

namespace EnumSelectorTest
{
  public class MainWindowVM : INotifyPropertyChanged
  {
    public EnumSelectorVM Selector { get; set; }

    private string _colorName;
    public string ColorName
    {
      get { return _colorName; }
      set
      {
        if (_colorName == value) return;
        _colorName = value;
        RaisePropertyChanged("ColorName");
      }
    }

    public MainWindowVM()
    {
      Selector = new EnumSelectorVM
        (
          typeof(MyColors),
          MyColors.Red,
          false,
          val => ColorName = "The color is " + ((MyColors)val).ToString()
        );
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void RaisePropertyChanged(string propertyName)
    {
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
  }
}

Die Klasse, die alle Arbeiten ausführt, erbt von DynamicObject. Von außen betrachtet erstellt es für jedes Element in enum eine bool - Eigenschaft mit dem Präfix 'Is', 'IsRed', 'IsBlue' usw., die an XAML gebunden werden kann. Zusammen mit einer Value-Eigenschaft, die den tatsächlichen enum -Wert enthält.

public enum MyColors
{
  Red,
  Magenta,
  Green,
  Cyan,
  Blue,
  Yellow
}

EnumSelectorVM

using System;
using System.ComponentModel;
using System.Dynamic;
using System.Linq;

namespace EnumSelectorTest
{
  public class EnumSelectorVM : DynamicObject, INotifyPropertyChanged
  {
    //------------------------------------------------------------------------------------------------------------------------------------------
    #region Fields

    private readonly Action<object> _action;
    private readonly Type _enumType;
    private readonly string[] _enumNames;
    private readonly bool _notifyAll;

    #endregion Fields

    //------------------------------------------------------------------------------------------------------------------------------------------
    #region Properties

    private object _value;
    public object Value
    {
      get { return _value; }
      set
      {
        if (_value == value) return;
        _value = value;
        RaisePropertyChanged("Value");
        _action?.Invoke(_value);
      }
    }

    #endregion Properties

    //------------------------------------------------------------------------------------------------------------------------------------------
    #region Constructor

    public EnumSelectorVM(Type enumType, object initialValue, bool notifyAll = false, Action<object> action = null)
    {
      if (!enumType.IsEnum)
        throw new ArgumentException("enumType must be of Type: Enum");
      _enumType = enumType;
      _enumNames = enumType.GetEnumNames();
      _notifyAll = notifyAll;
      _action = action;

      //do last so notification fires and action is executed
      Value = initialValue;
    }

    #endregion Constructor

    //------------------------------------------------------------------------------------------------------------------------------------------
    #region Methods

    //---------------------------------------------------------------------
    #region Public Methods

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
      string elementName;
      if (!TryGetEnumElemntName(binder.Name, out elementName))
      {
        result = null;
        return false;
      }
      try
      {
        result = Value.Equals(Enum.Parse(_enumType, elementName));
      }
      catch (Exception ex) when (ex is ArgumentNullException || ex is ArgumentException || ex is OverflowException)
      {
        result = null;
        return false;
      }
      return true;
    }

    public override bool TrySetMember(SetMemberBinder binder, object newValue)
    {
      if (!(newValue is bool))
        return false;
      string elementName;
      if (!TryGetEnumElemntName(binder.Name, out elementName))
        return false;
      try
      {
        if((bool) newValue)
          Value = Enum.Parse(_enumType, elementName);
      }
      catch (Exception ex) when (ex is ArgumentNullException || ex is ArgumentException || ex is OverflowException)
      {
        return false;
      }
      if (_notifyAll)
        foreach (var name in _enumNames)
          RaisePropertyChanged("Is" + name);
      else
        RaisePropertyChanged("Is" + elementName);
      return true;
    }

    #endregion Public Methods

    //---------------------------------------------------------------------
    #region Private Methods

    private bool TryGetEnumElemntName(string bindingName, out string elementName)
    {
      elementName = "";
      if (bindingName.IndexOf("Is", StringComparison.Ordinal) != 0)
        return false;
      var name = bindingName.Remove(0, 2); // remove first 2 chars "Is"
      if (!_enumNames.Contains(name))
        return false;
      elementName = name;
      return true;
    }

    #endregion Private Methods

    #endregion Methods

    //------------------------------------------------------------------------------------------------------------------------------------------
    #region Events

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void RaisePropertyChanged(string propertyName)
    {
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion Events
  }
}

Um auf Änderungen zu reagieren, können Sie entweder das NotifyPropertyChanged-Ereignis abonnieren oder eine anonyme Methode an den Konstruktor übergeben, wie oben beschrieben.

Und schließlich die MainWindow.xaml

<Window x:Class="EnumSelectorTest.MainWindow"
    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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">  
  <Grid>
    <StackPanel>
      <RadioButton IsChecked="{Binding Selector.IsRed}">Red</RadioButton>
      <RadioButton IsChecked="{Binding Selector.IsMagenta}">Magenta</RadioButton>
      <RadioButton IsChecked="{Binding Selector.IsBlue}">Blue</RadioButton>
      <RadioButton IsChecked="{Binding Selector.IsCyan}">Cyan</RadioButton>
      <RadioButton IsChecked="{Binding Selector.IsGreen}">Green</RadioButton>
      <RadioButton IsChecked="{Binding Selector.IsYellow}">Yellow</RadioButton>
      <TextBlock Text="{Binding ColorName}"/>
    </StackPanel>
  </Grid>
</Window>

Ich hoffe, jemand anderes findet das nützlich, weil ich davon ausgehe, dass diese in meine Toolbox gehen.

1
Brown Bear

Sie müssen den Gruppennamen für das Optionsfeld hinzufügen

   <StackPanel>
        <RadioButton Content="Button A" IsChecked="{Binding Path=ButtonAIsChecked, Mode=TwoWay}" GroupName="groupName" />
        <RadioButton Content="Button B" IsChecked="{Binding Path=ButtonBIsChecked, Mode=TwoWay}" GroupName="groupName" />
    </StackPanel>
1
ptsivakumar
<RadioButton  IsChecked="{Binding customer.isMaleFemale}">Male</RadioButton>
    <RadioButton IsChecked="{Binding customer.isMaleFemale,Converter=      {StaticResource GenderConvertor}}">Female</RadioButton>

Unten ist der Code für IValueConverter

public class GenderConvertor : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return !(bool)value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return !(bool)value;
    }
}

das hat für mich funktioniert. Sogar der Wert wurde durch Klicken auf das Optionsfeld sowohl für die Ansicht als auch für das Ansichtsmodell gebunden. True -> Male und False -> Female

0
jeevan

Ich habe ein sehr ähnliches Problem in VS2015 und .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">

....

Wie Sie in diesem Code sehen können, gibt es eine Listenansicht. Elemente in template sind Radiobuttons, die zu einem Gruppennamen gehören.

Wenn ich der Auflistung ein neues Element mit der Eigenschaft "Selected" auf "True" hinzufüge, wird es markiert und die restlichen Schaltflächen bleiben aktiviert.

Ich löse es, indem ich zuerst den checkedbutton besuche und manuell auf false setze. Dies ist jedoch nicht die Art und Weise, wie es gemacht werden soll.

code hinter:

`....
  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

`

0
Jose