【问题标题】:Accessing string value of Enum bound using EnumBoolConverter : IValueConverter使用 EnumBoolConverter 访问 Enum 绑定的字符串值:IValueConverter
【发布时间】:2011-09-28 02:29:37
【问题描述】:

首先,我希望我的问题的答案还没有出现。我已经搜索过,但似乎找不到我需要的东西。 其次,我对 C# 和 Silverlight 还是比较陌生。

我拥有的是一组使用转换器绑定到枚举的单选按钮。 这是我在 stackoverflow 上找到的代码。

我想不通的是如何在后面的代码中访问当前选中的单选按钮的值。

我已经设置了 DataContext:

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

绑定工作正常。反映选择不同的单选按钮。

我如何获得当前实际选择的按钮值?

例如)

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

如果选择了两个单选按钮,我将如何获得字符串值“Two”。

亲切的问候,

尼尔

这里会添加转换器代码,注释块太小了

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;

}

现在我完全错过了使用转换器和枚举来访问单击单选按钮的实际值的整个想法?

我是否应该只为每个单选按钮添加点击事件并在选中该单选按钮时设置一个变量?

这对五个单选按钮来说很好,但如果有很多呢。一定有更简单的方法。

亲切的问候

尼尔

【问题讨论】:

  • 只是一个评论:我认为上面的代码只是一个例子,因为将你的枚举命名为“List”是一个非常糟糕的主意:)

标签: silverlight binding datacontext


【解决方案1】:

一组 RadioButton 没有单一属性。您需要检查每个 RadioButton 的 IsChecked 状态。

应该可以使用转换器的 ConvertBack 将选定的按钮转换为枚举,但是将多个按钮绑定到相同的值会产生一些副作用。

如果您发布当前转换器的代码,我将了解如何提供合适的 ConvertBack 方法。

【讨论】:

  • 由于评论区太小,添加到mu原帖中
【解决方案2】:
Enum.GetName(typeof(List), selectedValue)

哇,这里按回车键有点太快了 :) 上面的代码有助于检索枚举的字符串值。

【讨论】:

  • 嗨 UrbanEsc,tx 的评论。 selectedValue 的值是多少?它是枚举的值吗?因此,如果我想要“二”回来,我使用 1 作为值?我认为这对我没有帮助,因为我仍然需要知道单击了哪个单选按钮才能知道值?
  • 是的,selectedValue 将是您的枚举值,如“List.Two”,它返回“Two”作为字符串。您可以像这样使用它:Enum.GetName(typeof(List), List.Two) - 返回“Two”。至于您的其他问题,我认为我对您的用例了解不足,无法帮助您解决问题。你想达到什么目标?一种解决方案可能是将 RadioBox 的“command”参数分配给视图模型的一个命令,并将 xamls 中的命令参数分别设置为“List.One”、“list.two”......然后该命令会查看它的内容参数是并且知道最后一个被点击的。
  • 至于我想要实现的目标:我的 XAML 代码中有 5 个单选按钮和一个数据网格。然后在我后面的代码中,我将一些数据分配给数据网格。我想要在数据网格中的列之一必须包含选中单选按钮的字符串值。分配您发送的命令参数的东西在我头上。我认为目前我将在每个 Radio Button 路由上执行整个 Click 事件。但是,我会经常回来查看,希望有一些建议可以让事情变得更有效。谢谢!
  • @Neill,我将为您添加另一个选项作为新答案。
【解决方案3】:

构建您自己的自定义过滤器控件。 首先,摆脱枚举,改用自定义类,它定义了可用的过滤器选项。我选择了一个名为“FilterOption”的类,它有一个名为“ColumnCriteriaName”的属性。您可以在应用程序的某处创建一个列表。

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

现在是时候创建您的自定义 silverlight 控件了。此控件的目的是接受 FilterOptions 列表并显示一组 Radiobuttons。每个按钮都是一个 FilterOption 值。当用户选择一个值时,您将收到通知。此控件将使用我试图描述的命令技术。

添加一个新控件,将其命名为“FilterOptionControl.xaml”。 Xaml 代码如下:

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

它只是一个带有 Stackpanel 的空控件,它将保存我们将在运行时创建的 RadioButtons。另请注意,我不会将 MVVM 用于此自定义控件,因为在这种情况下它会过度设计。当然,如果您愿意,可以随意将 MVVM 添加到此控件中,但我真的不推荐它。但是,您应该在更多特定于域的控件中使用 MVVM。

废话不多说,让我们为您的自定义控件粘贴 .cs 代码

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

如您所见,我们有两个依赖属性,它们都与更改的事件相关联,因此在设置它们时我们会收到通知(这样您可以为过滤器选项设置初始值 - 但是我没有立即实现它,你必须自己做这个)。

如果我们在 AvailableOptions 属性上设置了任何 FilterOptions,我们将触发我们的构建机制。我们清除 StackPanel 并为每个 FilterOption 添加一个新的 RadioButton。此外,我们将 RelayCommand 与此 RadioButtons 连接起来(有关命令说明,请参阅 http://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090051)并将 CommandParameter 设置为相应的 FilterOption。

因此,如果单选按钮被单击,则该命令将被触发,并将相应的 FilterOption 设置为 CommandParameter。我们现在将控件的 SelectedOption 设置为这个新值。

RelayCommand 的代码在这里,但取自我在上面发布的 msdn 链接(并稍作修改)

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

现在您可以根据需要在页面上使用此控件了。我在我的测试应用程序的主页中这样做了:

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

后面的代码是这样的:

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

我希望这会有所帮助。

它:当然,如果你仍然想使用你的枚举,你也可以使用 FilterOption 类,但我希望这段代码应该是一个好的开始。

【讨论】:

  • 非常感谢以上内容。我会做一些阅读,因为它超出了我目前的技能水平。我也请假2天,周四回办公室,到时候看看。一旦我有机会查看,将提供反馈和适当的解决方案等。发送一百万!
  • 没问题,您知道,您只需将该代码复制粘贴到一个新的 Silverlight 项目中即可。学习时拥有一个正在运行的应用程序总是有帮助的。
  • 嘿,尼尔,这对您的解决方案有帮助吗?如果是,请标记为答案。
  • 嗨 UrbanEsc。很抱歉现在才回到这个话题,但像往常一样,时间不在我这边。老实说,我没有机会尝试您的解决方案。我会将检查 IsChecked 状态的答案标记为对我有用的解决方案,因为它是我实现的。但是,如果我再次需要这样的东西,我会把你的想法放在脑海中。感谢一百万你的努力。尼尔
猜你喜欢
  • 1970-01-01
  • 2016-03-25
  • 2013-11-15
  • 2013-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-10
  • 1970-01-01
相关资源
最近更新 更多