0

The problem with my code is that RadioButton's binding and does not allow the delegate to modify the property. Delegate it changes, and binding, it changes to the old value. I am need to be able to change property by command and RadioButtons.

<Window.InputBindings>
    <KeyBinding Key="F1" Command="{Binding SomeCommand}"/>
</Window.InputBindings>
<StackPanel>
    <TextBlock Text="{Binding Path=SomeProperty}"/>
    <RadioButton IsChecked="{Binding Path=SomeProperty, Mode=TwoWay, Converter={StaticResource ETBConverter}, ConverterParameter=State1}" Content="State1"/>
    <RadioButton IsChecked="{Binding Path=SomeProperty, Mode=TwoWay, Converter={StaticResource ETBConverter}, ConverterParameter=State2}" Content="State2"/>
</StackPanel>

public enum TestEnum
{
    State1,
    State2,
}

public class TestViewModel : BaseViewModel
{
    private TestEnum _someProperty;

    public TestEnum SomeProperty
    {
        get { return _someProperty; }
        set
        {
            if (_someProperty != value)
            {
                _someProperty = value;
                OnPropertyChanged();
            }
        }
    }

    public Command SomeCommand { get; private set; }

    public TestViewModel()
    {
        _someProperty = TestEnum.State2;
        SomeCommand = new Command(SomeCommand_Execute);
    }

    private void SomeCommand_Execute(object obj)
    {
        SomeProperty = SomeProperty == TestEnum.State1 ? TestEnum.State2 : TestEnum.State1;
    }
}

Update 1:

[Localizability(LocalizationCategory.NeverLocalize)]
public class EnumToBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string parameterString = parameter as string;
        if (parameterString == null)
            return false;

        if (Enum.IsDefined(value.GetType(), value) == false)
            return false;

        object parameterValue = Enum.Parse(value.GetType(), parameterString);

        return parameterValue.Equals(value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string parameterString = parameter as string;
        if (parameterString == null)
            return DependencyProperty.UnsetValue;

        return Enum.Parse(targetType, parameterString);
    }
}
public abstract class BaseViewModel : NotifyPropertyChanged
{
    protected Dispatcher UIDispatcher;

    public BaseViewModel()
    {
        UIDispatcher = Dispatcher.CurrentDispatcher;
    }

    protected void InvokeInUIThread(Action action)
    {
        if (Thread.CurrentThread == UIDispatcher.Thread)
            action();
        else
            UIDispatcher.InvokeAsync(action, DispatcherPriority.Send);
    }
}
public abstract class NotifyPropertyChanged : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
public class Command : ICommand
{
    #region Fields

    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;

    #endregion // Fields

    #region Constructors

    public Command(Action<object> execute)
        : this(execute, null)
    {
    }

    public Command(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
        _canExecute = canExecute;
    }
    #endregion // Constructors

    #region ICommand Members

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    public void OnCanExecutedChanged()
    {
        CommandManager.InvalidateRequerySuggested();
    }

    #endregion // ICommand Members
}
Nodon
  • 967
  • 11
  • 24

3 Answers3

0

Use radiobutton list, it is must be more simple than use converter and you can do what you want. Look this answer

Community
  • 1
  • 1
Lance
  • 764
  • 1
  • 7
  • 18
0

I created below application based on code posted by you and it is working fine. Pressing F1 changes the Text of the TextBlock to State1. You can use the code as is.

Note : I have not used your ETBConverter as I don't have code for that. I believe that is some Enum To Boolean converter. You can see my code, and if that doesn't solve your issue. Tell me about your ETBConverter, I will look after it. Also, I don't have your BaseViewModel code, so I have implemented INotifyPropertyChanged interface.

MainWindow.xaml

<Window x:Class="WpfCommands.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.InputBindings>
        <KeyBinding Key="F1" Command="{Binding SomeCommand}"/>
    </Window.InputBindings>
    <Window.Resources>

    </Window.Resources>
    <StackPanel>
        <TextBlock Text="{Binding Path=SomeProperty}"/>
        <RadioButton IsChecked="{Binding Path=SomeProperty, Mode=TwoWay}" Content="State1"/>
        <RadioButton IsChecked="{Binding Path=SomeProperty, Mode=TwoWay}" Content="State2"/>
    </StackPanel>
</Window>

MainWindow.xaml.cs

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace WpfCommands
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new TestViewModel();
        }
    }

    public enum TestEnum
    {
        State1,
        State2,
    }

    public class TestViewModel : INotifyPropertyChanged
    {
        private TestEnum _someProperty;

        public TestEnum SomeProperty
        {
            get { return _someProperty; }
            set
            {
                if (_someProperty != value)
                {
                    _someProperty = value;
                    OnPropertyChanged("SomeProperty");
                }
            }
        }

        public Command SomeCommand { get; private set; }

        public TestViewModel()
        {
            _someProperty = TestEnum.State2;
            SomeCommand = new Command(SomeCommand_Execute);
        }

        private void SomeCommand_Execute(object obj)
        {
            SomeProperty = SomeProperty == TestEnum.State1 ? TestEnum.State2 : TestEnum.State1;
            System.Diagnostics.Debug.WriteLine("------------- executed ---------------");
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propname)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propname));
        }
    }

    public class Command : ICommand
    {
        public delegate void CommandExecuteHandler(object obj);
        CommandExecuteHandler handler;

        public Command(CommandExecuteHandler callback)
        {
            handler = callback;
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            handler(parameter);
        }
    }
}
AnjumSKhan
  • 9,647
  • 1
  • 26
  • 38
  • I added classes what you ask. – Nodon Nov 09 '15 at 05:50
  • when i press F1, TextBlock shows State1. I have double-checked. so code works fine. could u explain more about problem. – AnjumSKhan Nov 09 '15 at 06:44
  • SomeProperty = State2. When i press F1, command change SomeProperty to State1 and RadioButton binding change it back to State2 – Nodon Nov 09 '15 at 06:48
  • @Nodon Change Mode to OneWayToSource. By doing that your changes in RadioButton will be reflected in SomeProperty, but not vice-versa. Suppose you chose State2 RButton , then press F1, it will show State1, and vice-versa. – AnjumSKhan Nov 09 '15 at 07:12
0

Error was in EnumToBooleanCoverter.ConvertBack().

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
    if ((bool)value)
    {
        string parameterString = parameter as string;
        if (parameterString == null)
            return DependencyProperty.UnsetValue;

        return Enum.Parse(targetType, parameterString);
    }
    else
        return DependencyProperty.UnsetValue;
}

And it will be better to use extension

public class TestEnumExtension : TypedValueExtension<TestEnum>
{
    public TestEnumExtension(TestEnum value) : base(value) { }
}

public class TypedValueExtension<T> : MarkupExtension
{
    public TypedValueExtension(T value) { Value = value; }
    public T Value { get; set; }
    public override object ProvideValue(IServiceProvider sp) { return Value; }
}

New EnumToBolleanConverter

public class EnumToBooleanConverter : IValueConverter
{
    public object Convert(
        object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (TestEnum)value == (TestEnum)parameter;
    }

    public object ConvertBack(
        object value, Type targetType, object parameter, CultureInfo culture)
    {
        if ((bool)value)
            return parameter;
        else
            return DependencyProperty.UnsetValue;
    }
}

and XAML

<RadioButton IsChecked="{Binding Path=SomeProperty, Mode=TwoWay, 
    Converter={StaticResource ETBConverter}, ConverterParameter={exten:TestEnum State1}}"
             Content="State1"/>
<RadioButton IsChecked="{Binding Path=SomeProperty, Mode=TwoWay, 
    Converter={StaticResource ETBConverter}, ConverterParameter={exten:TestEnum State2}}"
             Content="State2"/>
Nodon
  • 967
  • 11
  • 24