开发者

Accessing string value of Enum bound using EnumBoolConverter : IValueConverter

Firstly I hope the answer to my question is not already here. I have searched but can't seem to find what I need. Secondly, I am still rather new to C# and Silverlight.

What I have is a group of Radio Buttons bound to an Enum using a Converter. This is code I have found on stackoverflow.

What I can't figure out is how to access the value of the currently selected Radio Button in the code behind.

I have set the DataContext:

public pgThePage()
{
    InitializeComponent();
    DataContext = new ViewModel();   
}

The binding is working fine. Selecting different Radio Button is reflected.

How do I then get the actual cur开发者_Go百科rently selected button value though?

Eg)

public enum List
{
    One,
    Two,
    Three,
    Four,
    Five,
}

How would I get the string value "Two" if the Two Radio Button was selected.

Kind regards,

Neill

Will add the Converter Code here, comment block is too small

public class EnumBoolConverter : IValueConverter
{

    public object Convert(object value, Type targetType, object parameter,  System.Globalization.CultureInfo culture)
    {
        if (value == null || parameter == null)
            return value;

        return value.ToString() == parameter.ToString();
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null || parameter == null)
            return value;

        return Enum.Parse(targetType, (String)parameter, true);

    }
}

public enum ClientsList
{
    One,
    Two,
    Three,
    Four,
    Five,
}

public class ViewModel : INotifyPropertyChanged
{
    private ClientsList _clientsList;

    public ClientsList clientsList
    {
        get
        {
            return _clientsList;
        }
        set
        {
            if (_clientsList != value)
            {
                _clientsList = value;
                RaisePropertyChanged("clientsList");
            }
        }
    }

    public virtual void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

}

Now I am completely missing the whole idea of using a converter and enums to access the actual value of the clicked radio button?

Should I just go the route of adding a click event to each Radio Button and setting a variable if that Radio Button is checked?

That would be fine for five Radio Buttons, but what about having a whole lot. There must be an easier way.

Kind regards

Neill


There is no single property for a group of RadioButtons. You need to check the IsChecked state of each RadioButton.

It should be possible to use a converter's ConvertBack to turn a selected button into an enum, but having multiple buttons bound to the same value will have some side-effects.

If you post the code for your current converter I will see about providing a suitable ConvertBack method.


Enum.GetName(typeof(List), selectedValue)

Wow, hit that return key a bit too fast here :) The above code helps retrieving the string value of your enum.


Build your own custom filter control. First, get rid of the enum, use a custom class instead, that defines your available filter options. I choose a class named "FilterOption", which has a property named "ColumnCriteriaName". You would create a list of those somewhere in your application.

public class FilterOption
{
    public string ColumnNameCriteria { get; set; }
}

Now its time to create your custom silverlight control. The purpose of this control is the accept a list of FilterOptions and display a set of Radiobuttons. Each button will be a FilterOption value. When the user selects a value, you will get notified. This control will use the Commanding techniques i tried to describe.

Add a new control, name it "FilterOptionControl.xaml". The Xaml Code is as follows:

<UserControl x:Class="SilverlightApplication1.FilterOptionControl"
    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"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <StackPanel x:Name="stacker" />
    </Grid>
</UserControl>

Its just an empty control with a Stackpanel which will hold our RadioButtons which we will create at runtime. Also please note that i will not use MVVM for this custom control, because in this case it would be over-engineering. Of course, feel free to add MVVM to this control if you want to, but i really dont recommend it. You should however use MVVM in your more domain specific controls.

Enought talk, lets just paste in the .cs code for your custom control

public partial class FilterOptionControl : UserControl
{
    public IEnumerable<FilterOption> AvailableOptions
    {
        get { return (IEnumerable<FilterOption>)GetValue(AvailableOptionsProperty); }
        set { SetValue(AvailableOptionsProperty, value); }
    }

    public static readonly DependencyProperty AvailableOptionsProperty = DependencyProperty.Register(
        "AvailableOptions", 
        typeof(IEnumerable<FilterOption>),
        typeof(FilterOptionControl), new PropertyMetadata(OnPropertyChangedCallback));



    public FilterOption SelectedOption
    {
        get { return (FilterOption)GetValue(SelectedOptionProperty); }
        set { SetValue(SelectedOptionProperty, value); }
    }

    public static readonly DependencyProperty SelectedOptionProperty = DependencyProperty.Register(
        "SelectedOption", 
        typeof(FilterOption), 
        typeof(FilterOptionControl),
        new PropertyMetadata(OnPropertyChangedCallback));

    protected static void OnPropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        if (sender is FilterOptionControl)
            ((FilterOptionControl)sender).OnPropertyChanged(args);
    }

    private void OnPropertyChanged(DependencyPropertyChangedEventArgs args)
    {
        if (args.Property == AvailableOptionsProperty)
        {
            RebuildFilterOptions();
        }
    }

    public FilterOptionControl()
    {
        InitializeComponent();

        SelectedValueChangedCommand = new RelayCommand(
            new Action<object>(this.ChangeSelectedValue));
    }

    RelayCommand SelectedValueChangedCommand;
    void ChangeSelectedValue(object option)
    {
        SelectedOption = option as FilterOption;
    }

    private void RebuildFilterOptions()
    {
        stacker.Children.Clear();

        if (AvailableOptions != null)
        {
            foreach (FilterOption option in AvailableOptions)
            {
                RadioButton btt = new RadioButton();
                btt.Content = option.ColumnNameCriteria;
                btt.Command = SelectedValueChangedCommand;
                btt.CommandParameter = option;
                stacker.Children.Add(btt);
            }
        }
    }
}

As you can see we have two dependency properties which are both wired up with changed events so we get notified when they get set (this way you could set an initial value for the filter options - however i didnt implement it straight away, youll have to do this yourself).

If we get set any FilterOptions on the AvailableOptions Property, we will trigger our build mechanism. We clear the StackPanel and add a new RadioButton for every FilterOption. Additionally we wire up a RelayCommand with this RadioButtons (see http://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090051 for command explanation) and set the CommandParameter to the respective FilterOption.

So if a RadioButton gets clicked, this command gets fired with the corresponding FilterOption set as the CommandParameter. We now set the SelectedOption of our control to this new value.

The code for the RelayCommand is here, but is taken (and slightly modified) from the msdn link i posted above

public class RelayCommand : ICommand
{
    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;

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

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

        _execute = execute;
        _canExecute = canExecute;
    }

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

    public event EventHandler CanExecuteChanged;

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

Now you are ready to use this control on a page as you like. I did it like so in the main page of my test app:

<UserControl x:Class="SilverlightApplication1.MainPage" *snip*
             x:Name="me">

    <Grid x:Name="LayoutRoot" Background="White">

        <StackPanel>
            <TextBlock  Text="{Binding ElementName=filter, Path=SelectedOption.ColumnNameCriteria, FallbackValue='none'}"/>
            <this:FilterOptionControl x:Name="filter"
                AvailableOptions="{Binding ElementName=me, Path=MyFilterOptions}" />

        </StackPanel>
    </Grid>
</UserControl>

and the code behind looks like this:

public partial class MainPage : UserControl
{
    public IEnumerable<FilterOption> MyFilterOptions
    {
        get { return (IEnumerable<FilterOption>)GetValue(MyFilterOptionsProperty); }
        set { SetValue(MyFilterOptionsProperty, value); }
    }

    public static readonly DependencyProperty MyFilterOptionsProperty =
        DependencyProperty.Register(
        "MyFilterOptions", 
        typeof(IEnumerable<FilterOption>), 
        typeof(MainPage), 
        new PropertyMetadata(null));

    public MainPage()
    {
        InitializeComponent();

        MyFilterOptions = new List<FilterOption> 
        { 
            new FilterOption() { ColumnNameCriteria = "One"},
            new FilterOption() { ColumnNameCriteria = "Two"},
            new FilterOption() { ColumnNameCriteria = "Three"}
        };
    }
}

I hope that helped.

it: Of course, if you still want to use your enums, you can do so too using the FilterOption class, but this code should be a good start for your i hope.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜