Вопрос

I am writing a simple program using the MVVM Model on WPF. Basicly when the user clicks a radio button in a group of radio buttons, it will update a property in the View Model with the new Account number. The problem is, when I click a different button the converter is called for the new button IsChecked Binding, and then after that it runs the converter for the previous button IsChecked binding(for losing its checked status).

This is causing a problem, since the new button is updating the value of the property with the correct account number, and then when the old button calls the converter, it gets converted back to the old value. I have hacked it to work by adding a static variable to the class, and if the IsChecked property is false, just return the value in the static variable. Does anyone have a better solution for Short Circuting the Converter Call on the box that loses its checked status. Code is below:

Converter:

class RadioToAccountConverter : IValueConverter
{
    static string myValue; //HACK TO MAKE IT WORK
    object IValueConverter.Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return parameter.ToString();
    }

    object IValueConverter.ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {

        if ((bool)value)
        {
            myValue = parameter.ToString(); // Hack to make it work
            return parameter.ToString();
        }
        return myValue; // Hack to make it work
    }
}

XAML:

                <RadioButton Foreground="HotPink" 
                             Grid.Column="0" 
                             Content="6087721" 
                             Tag="6087721"
                             IsChecked="{Binding Account, Converter={StaticResource Radio2Value}, Mode=OneWayToSource, ConverterParameter=6087721}">
                </RadioButton>

                <RadioButton Foreground="HotPink" 
                             Grid.Column="1"
                             Content="BFSC120"
                             IsChecked="{Binding Account, Converter={StaticResource Radio2Value}, Mode=OneWayToSource, ConverterParameter='BFSC120'}">
                </RadioButton>

                <RadioButton Foreground="HotPink" 
                             Grid.Column="2"
                             Content="BFSC121"
                             IsChecked="{Binding Account, Converter={StaticResource Radio2Value}, Mode=OneWayToSource, ConverterParameter=BFSC121}">
                </RadioButton>

                <RadioButton Foreground="HotPink" 
                             Grid.Column="3" 
                             Content="BFSC206" 
                             IsChecked="{Binding Account, Converter={StaticResource Radio2Value}, Mode=OneWayToSource, ConverterParameter=BFSC206}">

                </RadioButton>

Property:

    public const string AccountPropertyName = "Account";

    private string _account;

    /// <summary>
    /// Sets and gets the Account property.
    /// Changes to that property's value raise the PropertyChanged event. 
    /// </summary>
    public string Account
    {
        get
        {
            return _account;
        }

        set
        {
            if (_account == value)
            {
                return;
            }

            RaisePropertyChanging(AccountPropertyName);
            _account = value;
            RaisePropertyChanged(AccountPropertyName);
        }
    }

Any Help Is Greatly Appreciated.

Это было полезно?

Решение 2

If you define a GroupName on each RadioButton, WPF will manage the IsChecked states for you.

You could bind the state with a {Binding SomeProperty, Mode=OneWayToSource} if you want the ViewModel to be aware of state.

One way to approach this would be to bind each RadioButton's IsChecked property to the whole ViewModel, just bind it to something like

IsChecked="{Binding WholeViewModel, Mode=OneWayToSource, Converter={StaticResource MyRadioButtonConverter}, ConverterParameter=SomethingReallyUnique}"

...where the public property WholeViewModel is a property that does a return this; in the getter. This would let you have access to the ViewModel and enough information to query the ViewModel to see if the radiobutton should be checked or not. But, only do this if the GroupName DependencyProperty doesn't somehow give you what you want.

To process the clicking on the buttons, then, to actually change the ViewModel state, you'd implement an ICommand in your ViewModel and bind the Command property of the RadioButton to {Binding ClickedCommand} and define a CommandParameter with any string you want. This approach will guarantee a one-way relationship to the IsChecked state, preventing the thing you're describing, I think.

I'll work up a code sample if you think you'd like one.

Другие советы

Based on what I understand, you want to give users the ability to select from a list of account numbers. You're choice of presentation (view) is a group of radio buttons.

If that is true, the key part is this: you want to give users the ability to select from a list of account numbers. This means that the control you should use is a ListBox, since users should select one of the appropriate values. Now, since you are looking to use radio buttons visually, you simply have to supply an alternative ItemsSource.ItemContainerStyle.


XAML:

<ListBox ItemsSource="{Binding AccountNumbers, Mode=OneWay">
  <ListBox.ItemContainerStyle>
    <Style TargetType="{x:Type ListBoxItem}">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type ListBoxItem}">
            <RadioButton Content="{Binding}" IsChecked="{Binding IsSelected, RelativeSource={x:Static RelativeSource.TemplatedParent}}"/>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
  </ListBox.ItemContainerStyle>
</ListBox>

Note that you'll need to add another property on your ViewModel (I named it AccountNumbers). For example:

public IReadOnlyCollection<string> AccountNumbers { ... }

Of course, the underlying collection can be a observable if you need it to be, but that's really up to you.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top