문제

데이터 객체에 옵션 목록이 있으며 사용자가 하나만 선택할 수 있도록 라디오 버튼 목록과 동일하게 만들고 싶습니다. 데이터 바운드 콤보 상자와 유사하지만 라디오 버튼 형식으로 기능합니다.

바보, 나는 이것이 내장 될 것이라고 생각했지만 아니요. 어떻게 하시나요?

도움이 되었습니까?

해결책

기본적으로 Google 결과를 검토 한 후 정보를 시작했습니다. WPF 박사가 답을 제공 한 MSDN 토론 스레드, Listbox 스타일링에 대해 이야기합니다. 그러나 Listbox가 비활성화되면 배경은 내가 읽을 때까지 내 인생을 제거 할 수없는 성가신 색상이었습니다. ListBox ControlTemplate의 MSDN 예제입니다, 이것은 내 배경 엉덩이를 차고있는 비밀 테두리 요소를 보여줍니다.

여기서 마지막 답변은이 스타일이었습니다.

<Style x:Key="RadioButtonList" TargetType="{x:Type ListBox}">
    <!-- ControlTemplate taken from MSDN http://msdn.microsoft.com/en-us/library/ms754242.aspx -->
    <Setter Property="SnapsToDevicePixels" Value="true"/>
    <Setter Property="OverridesDefaultStyle" Value="true"/>
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
    <Setter Property="MinWidth" Value="120"/>
    <Setter Property="MinHeight" Value="95"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBox">
                <Border Name="Border" Background="Transparent"
                        BorderBrush="Transparent"
                        BorderThickness="0"
                        CornerRadius="2">
                    <ScrollViewer Margin="0" Focusable="false">
                        <StackPanel Margin="2" IsItemsHost="True" />
                    </ScrollViewer>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter TargetName="Border" Property="Background"
                                Value="Transparent" />
                        <Setter TargetName="Border" Property="BorderBrush"
                                Value="Transparent" />
                    </Trigger>
                    <Trigger Property="IsGrouping" Value="true">
                        <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="ItemContainerStyle">
        <Setter.Value>
            <Style TargetType="{x:Type ListBoxItem}" >
                <Setter Property="Margin" Value="2" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ListBoxItem}">
                            <Border Name="theBorder" Background="Transparent">
                                <RadioButton Focusable="False" IsHitTestVisible="False"
                                             IsChecked="{TemplateBinding IsSelected}">
                                    <ContentPresenter />
                                </RadioButton>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Setter.Value>
    </Setter>
</Style>

이것은 목록 상자 및 항목에 대한 제어판 및 스타일을 제공합니다. 그리고 다음과 같이 사용됩니다.

<ListBox Grid.Column="1" Grid.Row="0" x:Name="TurnChargeBasedOnSelector" Background="Transparent"
    IsEnabled="{Binding Path=IsEditing}"
    Style="{StaticResource RadioButtonList}"
    ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:MainForm}}, Path=DataContext.RampTurnsBasedOnList}"
    DisplayMemberPath="Description" SelectedValuePath="RampTurnsBasedOnID"
    SelectedValue="{Binding Path=RampTurnsBasedOnID, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}"/>

WPF와 함께 시간을 더 많이 보낼수록 사소한 일이 어렵고 사소한 사소한 일을 더 많이 생각합니다. 즐기다. -스콧

다른 팁

속성 이름이있는 개체 목록이있는 ListBox의 항목 소스에 ListBox를 바인딩합니다 (변경 될 수 있음)

<ListBox Name="RadioButtonList">
   <ListBox.ItemTemplate >
        <DataTemplate >
             <RadioButton GroupName="radioList" Tag="{Binding}" Content="{Binding Name}"/>
         </DataTemplate>
                                                    </ListBox.ItemTemplate>
                                                </ListBox>

중요한 GroupName = "radiolist"

나는 이것을 통해 이것을했다 ValueConverter 그것은 변환합니다 enum a bool. 라디오 버튼이 나타내는 열거 값을 전달함으로써 ConverterParameter, 변환기는이 라디오 버튼을 확인 해야하는지 여부를 반환합니다.

<Window.Resources>
    <Converters:EnumConverter x:Key="EnumConverter" />
</Window.Resources>

<RadioButton IsChecked="{Binding Path=MyEnum, Mode=TwoWay, 
                                 Converter={StaticResource EnumConverter}, 
                                 ConverterParameter=Enum1}"}
             Content="Enum 1" />
<RadioButton IsChecked="{Binding Path=MyEnum, Mode=TwoWay, 
                                 Converter={StaticResource EnumConverter}, 
                                 ConverterParameter=Enum2}"}
             Content="Enum 2" />

EnumConverter 다음과 같이 정의됩니다.

public class EnumConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (targetType.IsAssignableFrom(typeof(Boolean)) && targetType.IsAssignableFrom(typeof(String)))
                throw new ArgumentException("EnumConverter can only convert to boolean or string.");
            if (targetType == typeof(String))
                return value.ToString();

            return String.Compare(value.ToString(), (String)parameter, StringComparison.InvariantCultureIgnoreCase) == 0;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (targetType.IsAssignableFrom(typeof(Boolean)) && targetType.IsAssignableFrom(typeof(String)))
                throw new ArgumentException("EnumConverter can only convert back value from a string or a boolean.");
            if (!targetType.IsEnum)
                throw new ArgumentException("EnumConverter can only convert value to an Enum Type.");

            if (value.GetType() == typeof(String))
            {
                return Enum.Parse(targetType, (String)value, true);
            }

            //We have a boolean, as for binding to a checkbox. we use parameter
            if ((Boolean)value)
                return Enum.Parse(targetType, (String)parameter, true);

            return null;
        }
    }

라디오 버튼을 생성하기 위해 열거 목록에 데이터베이션을하지 않으며 손으로 수행했습니다. 바인딩을 통해 라디오 버튼 목록을 채우고 싶다면 IsChecked a에 바인딩 MultiBinding 바인딩을 사용할 수 없기 때문에 현재 값과 라디오의 열거 값에 결합합니다. ConverterParameter.

매우 간단하고 MVVM 친화적이며 유형에 대한 데이터 emplate를 활용합니다. XAML :

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    Title="MainWindow" Height="350" Width="525">

<Window.Resources>
    <DataTemplate DataType="{x:Type local:Option}">
        <RadioButton Focusable="False"
                IsHitTestVisible="False"
                Content="{Binding Display}"
                IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem}}">
        </RadioButton>
    </DataTemplate>
</Window.Resources>

<Grid>
    <ListBox ItemsSource="{Binding Options}" SelectedItem="{Binding SelectedOption}"/>
</Grid>

모델보기 등 :

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new Vm();
    }
}

public class Vm
{
    public Option[] Options { get { return new Option[] { 
        new Option() { Display = "A" }, 
        new Option() { Display = "B" }, 
        new Option() { Display = "C" } }; } }
    public Option SelectedOption { get; set; }
}

public class Option
{
    public string Display { get; set; }
}

옵션을 특정 유형으로 랩핑하는 경우 (또는 이미 가능성이 있음). 해당 유형의 데이터 템플릿을 설정할 수 있습니다. WPF는 자동으로 사용합니다. (ListBox 리소스에서 DataTemplate을 정의하여 DataTemplate의 적용되는 범위를 제한하십시오).

또한 DataTemplate에서 그룹 이름을 사용하여 원하는 경우 그룹을 설정하십시오.

이것은 제어 템플릿을 변경하는 것보다 훨씬 간단하지만 선택한 항목에 파란색 선이 있음을 의미합니다. (다시 한 번, 약간의 스타일은 고칠 수 없습니다).

WPF는 방법을 알면 간단합니다.

죄송합니다. Scott O의 게시물에 대한이 답변을 그의 게시물에 대한 의견으로 말하고 싶습니다. 그러나 아직 그렇게하는 명성은 없습니다. 스타일 전용 솔루션 이었기 때문에 그의 대답이 마음에 들었으므로 추가 코드를 추가하거나 사용자 정의 제어 등을 만들 필요가 없었습니다.

그러나 ListBoxItems 내부에서 컨트롤을 사용해 보려고했을 때 한 가지 문제가있었습니다. 이 스타일을 사용할 때는이 라인으로 인해 포함 된 컨트롤에 초점을 맞출 수 없습니다.

<RadioButton Focusable="False" IsHitTestVisible="False" IsChecked="{TemplateBinding IsSelected}">

라디오 버튼은 올바르게 작동하기 위해 초점을 맞출 수 있고 ishittestvesible을 끄야합니다. 이 문제를 해결하기 위해 템플릿 결합에서 정기적 인 바인딩으로 Ischecked를 변경하여 양방향 바인딩으로 만들 수있었습니다. 불쾌한 설정을 제거하면이 라인이 나에게 제공되었습니다.

<RadioButton IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected, Mode=TwoWay}">

이제 예상대로 ListBoxItems에 포함 된 컨트롤에 집중할 수 있습니다.

도움이 되었기를 바랍니다.

나는 영감을 얻었습니다 Jon Benson의 블로그 항목, 그러나 설명 속성이있는 열거를 사용하기 위해 솔루션을 수정했습니다. 그래서 솔루션의 주요 부분은 다음과 같습니다.

설명이있는 열거 자

public enum AgeRange {
  [Description("0 - 18 years")]
  Youth,
  [Description("18 - 65 years")]
  Adult,
  [Description("65+ years")]
  Senior,
}

읽기 설명 및 바인딩을위한 키/값 쌍을 반환하기위한 코드.

public static class EnumHelper
{
    public static string ToDescriptionString(this Enum val)
    {
        var attribute =
            (DescriptionAttribute)
            val.GetType().GetField(val.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false).
                SingleOrDefault();
        return attribute == default(DescriptionAttribute) ? val.ToString() : attribute.Description;
    }

    public static List<KeyValuePair<string,string>> GetEnumValueDescriptionPairs(Type enumType)
    {
        return Enum.GetValues(enumType)
            .Cast<Enum>()
            .Select(e => new KeyValuePair<string, string>(e.ToString(), e.ToDescriptionString()))
            .ToList();
    }
}

XAML의 객체 데이터 제공자

<ObjectDataProvider
    ObjectType="{x:Type local:EnumHelper}"
    MethodName="GetEnumValueDescriptionPairs"
    x:Key="AgeRanges">
    <ObjectDataProvider.MethodParameters>
        <x:Type TypeName="local:AgeRange" />
    </ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

XAML의 ListBox

<ListBox 
    ItemsSource="{Binding Source={StaticResource AgeRanges}}"
    SelectedValue="{Binding SelectedAgeRange}"
    SelectedValuePath="Key">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <RadioButton 
                IsChecked="{Binding IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}"
                Content="{Binding Value}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

당신이 구속력있는 속성 (예 : 당신의보기 모델)

public class YourViewModel : INotifyPropertyChanged
{
  private AgeRange _selectedAgeRange;
  public AgeRange SelectedAgeRange
  {
    get { return _selectedAgeRange; }
    set 
    {
      if (value != _selectedAgeRange)
      {
        _selectedAgeRange = value;
        OnPropertyChanged("SelectedAgeRange");
      }
    }
  }
}

나는 속임수 :

내 해결책은 저에게 효과적인 것처럼 보이는 전부이기 때문에 목록 상자를 프로그래밍 방식으로 바인딩하는 것이 었습니다.

            if (mUdData.Telephony.PhoneLst != null)
            {
                lbPhone.ItemsSource = mUdData.Telephony.PhoneLst;
                lbPhone.SelectedValuePath = "ID";
                lbPhone.SelectedValue = mUdData.Telephony.PrimaryFaxID;
            }

XAML은 다음과 같습니다.

                        <ListBox.ItemTemplate >

                        <DataTemplate >
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition></RowDefinition>
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto"></ColumnDefinition>
                                    <ColumnDefinition Width="Auto"></ColumnDefinition>
                                </Grid.ColumnDefinitions>

                                <RadioButton 
                                    IsChecked="{Binding Path=PrimaryPhoneID}" 
                                    GroupName="Phone" 
                                    x:Name="rbPhone"
                                    Content="{Binding Path=PrimaryPhoneID}"
                                    Checked="rbPhone_Checked"/>

                                <CheckBox Grid.Column="2" IsEnabled="False" IsChecked="{Binding Path=Active}" Content="{Binding Path=Number}" ></CheckBox>

                            </Grid>
                        </DataTemplate>
                    </ListBox.ItemTemplate>

그리고 내 이벤트에서 선택된 라디오 버튼의 값을 읽는 것은 다음과 같습니다.

    private void rbPhone_Checked(object sender, RoutedEventArgs e)
    {
        DataRowView dvFromControl = null;
        dvFromControl = (DataRowView)((RadioButton)sender).DataContext;

        BindData.Telephony.PrimaryPhoneID = (int)dvFromControl["ID"];

    }

그것이 누군가를 돕기를 바랍니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top