互斥复选框 - C#,MVVM

3

我正在编写一个程序,将有两种可能性:手动设置时间和日期或使用计算机/系统时间和日期。

现在我需要创建两个互斥的复选框。当选择一个时,另一个必须取消选中。在MVVM模式下如何实现?

<CheckBox Name="UseSystemTime" Margin="7"  Content="Use System Time and Date settings (Time, Date, DST, Timezone)" IsChecked="{Binding UseSystemTime}"/>
<CheckBox Name="ManualTime" Margin="7"  Content="Set settings Manually" IsChecked="{Binding SetSettingsManually}"/>

有没有一种在XAML中实现这个功能的方法?
感谢WPF数据绑定互斥复选框编程的帮助!

如果有任何问题,请随时提问。 - esispaned
6
为什么不使用单选按钮呢?它们是显示互斥选项的传统方式,而且可能更容易设置。 - Nanhydrin
谢谢你的建议。我也考虑过这个问题。但是复选框的形式更美观(更用户友好)- 我这么认为 :) 我宁愿使用复选框,或者是否可以将单选按钮的形状改成复选框的形式呢?:) 带有勾选标记和所有的东西?:) - esispaned
2
您应该始终询问用户的喜好,在制作任何类型的软件时不应仅考虑自己的观点。当需要互斥行为时,使用具有默认外观的单选按钮是标准行为。将默认外观更改为其他标准控件可能会让用户感到困惑。能够做某事并不意味着您总是应该这样做。 - LightBulb
在所有这些评论之后,如果你仍然想要使用你之前的方式,那么你需要为你的IsChecked属性添加一个转换器。可能是一个带有MultiBinding的转换器。 - Ugur
在技术上,你只需要一个 CheckBox。当勾选时,使用系统时间;否则,用户需要手动设置。用户界面应该简单、易懂且直接,不一定要漂亮。 - LightBulb
3个回答

1

如果你只有2个复选框,我会在我的视图模型中引入一个名为ManualTime的布尔属性。

public bool IsManualTimeUsed
{
   // get;set with property-changed 
}

在用户界面中,您有两个机会:
机会1:
 <CheckBox Name="UseSystemTime" Margin="7" Content="Use System Time and Date settings (Time, Date, DST, Timezone)" 
           IsChecked="{Binding IsManualTimeUsed, Converter{converterNamespace:InverseBoolConverter}}"/>
 <CheckBox Name="ManualTime" Margin="7" Content="Set settings Manually" 
           IsChecked="{Binding IsManualTimeUsed}"/>

其中InverseBoolConverter可以看起来像:

public class InverseBoolConverter : MarkupExtension, IValueConverter
{
    private static InverseBoolConverter converter;

    public InverseBoolConverter()
    {

    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is bool)
            return !((bool) value);
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return converter ?? (converter = new InverseBoolConverter());
    }
}

Opportunity 2

<CheckBox Name="UseSystemTime" Margin="7" Content="Use System Time and Date settings (Time, Date, DST, Timezone)" 
          IsChecked="{Binding ElementName=ManualTime, Path=IsChecked, Converter={converterNamespace:InverseBoolConverter}}"/>
<CheckBox Name="ManualTime" Margin="7" Content="Set settings Manually" 
          IsChecked="{Binding IsManualTimeUsed}"/>

使用与机会1中相同的转换器。

我正在尝试使用"Opportunity 2",但是出现了错误:"InverseBoolConverter在Windows Presentation Foundation (WPF)项目中不受支持。"为什么会出现这个错误呢?我在视图模型中同时实现了XAML代码和C#代码。 - esispaned
我建议将转换器放在名为"Converter"的单独文件夹中。然后在XAML文件的Window声明中,您需要使用xmlns:converter=PATHTOCONVERTER来包含它,这样您就可以使用它了。 - Tomtom

0

0
但是复选框的形式更美观(更用户友好)-我这么认为 :) 我宁愿使用复选框,或者将单选按钮的形状改变为复选框形式?:) 带有勾选标记和所有内容? :)
您可以创建一个样式来使RadioButton看起来像CheckBox:
    <Style x:Key="FocusVisual">
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate>
                    <Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <SolidColorBrush x:Key="OptionMark.Static.Background" Color="#FFFFFFFF"/>
    <SolidColorBrush x:Key="OptionMark.Static.Border" Color="#FF707070"/>
    <Style x:Key="OptionMarkFocusVisual">
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate>
                    <Rectangle Margin="14,0,0,0" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <SolidColorBrush x:Key="OptionMark.MouseOver.Background" Color="#FFF3F9FF"/>
    <SolidColorBrush x:Key="OptionMark.MouseOver.Border" Color="#FF5593FF"/>
    <SolidColorBrush x:Key="OptionMark.MouseOver.Glyph" Color="#FF212121"/>
    <SolidColorBrush x:Key="OptionMark.Disabled.Background" Color="#FFE6E6E6"/>
    <SolidColorBrush x:Key="OptionMark.Disabled.Border" Color="#FFBCBCBC"/>
    <SolidColorBrush x:Key="OptionMark.Disabled.Glyph" Color="#FF707070"/>
    <SolidColorBrush x:Key="OptionMark.Pressed.Background" Color="#FFD9ECFF"/>
    <SolidColorBrush x:Key="OptionMark.Pressed.Border" Color="#FF3C77DD"/>
    <SolidColorBrush x:Key="OptionMark.Pressed.Glyph" Color="#FF212121"/>
    <SolidColorBrush x:Key="OptionMark.Static.Glyph" Color="#FF212121"/>
    <Style x:Key="CheckBoxRadioButtonStyle" TargetType="{x:Type RadioButton}">
        <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
        <Setter Property="Background" Value="{StaticResource OptionMark.Static.Background}"/>
        <Setter Property="BorderBrush" Value="{StaticResource OptionMark.Static.Border}"/>
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type RadioButton}">
                    <Grid x:Name="templateRoot" Background="Transparent" SnapsToDevicePixels="True">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <Border x:Name="checkBoxBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
                            <Grid x:Name="markGrid">
                                <Path x:Name="optionMark" Data="F1 M 9.97498,1.22334L 4.6983,9.09834L 4.52164,9.09834L 0,5.19331L 1.27664,3.52165L 4.255,6.08833L 8.33331,1.52588e-005L 9.97498,1.22334 Z " Fill="{StaticResource OptionMark.Static.Glyph}" Margin="1" Opacity="0" Stretch="None"/>
                                <Rectangle x:Name="indeterminateMark" Fill="{StaticResource OptionMark.Static.Glyph}" Margin="2" Opacity="0"/>
                            </Grid>
                        </Border>
                        <ContentPresenter x:Name="contentPresenter" Grid.Column="1" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="HasContent" Value="true">
                            <Setter Property="FocusVisualStyle" Value="{StaticResource OptionMarkFocusVisual}"/>
                            <Setter Property="Padding" Value="4,-1,0,0"/>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="Background" TargetName="checkBoxBorder" Value="{StaticResource OptionMark.MouseOver.Background}"/>
                            <Setter Property="BorderBrush" TargetName="checkBoxBorder" Value="{StaticResource OptionMark.MouseOver.Border}"/>
                            <Setter Property="Fill" TargetName="optionMark" Value="{StaticResource OptionMark.MouseOver.Glyph}"/>
                            <Setter Property="Fill" TargetName="indeterminateMark" Value="{StaticResource OptionMark.MouseOver.Glyph}"/>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Background" TargetName="checkBoxBorder" Value="{StaticResource OptionMark.Disabled.Background}"/>
                            <Setter Property="BorderBrush" TargetName="checkBoxBorder" Value="{StaticResource OptionMark.Disabled.Border}"/>
                            <Setter Property="Fill" TargetName="optionMark" Value="{StaticResource OptionMark.Disabled.Glyph}"/>
                            <Setter Property="Fill" TargetName="indeterminateMark" Value="{StaticResource OptionMark.Disabled.Glyph}"/>
                        </Trigger>
                        <Trigger Property="IsPressed" Value="true">
                            <Setter Property="Background" TargetName="checkBoxBorder" Value="{StaticResource OptionMark.Pressed.Background}"/>
                            <Setter Property="BorderBrush" TargetName="checkBoxBorder" Value="{StaticResource OptionMark.Pressed.Border}"/>
                            <Setter Property="Fill" TargetName="optionMark" Value="{StaticResource OptionMark.Pressed.Glyph}"/>
                            <Setter Property="Fill" TargetName="indeterminateMark" Value="{StaticResource OptionMark.Pressed.Glyph}"/>
                        </Trigger>
                        <Trigger Property="IsChecked" Value="true">
                            <Setter Property="Opacity" TargetName="optionMark" Value="1"/>
                            <Setter Property="Opacity" TargetName="indeterminateMark" Value="0"/>
                        </Trigger>
                        <Trigger Property="IsChecked" Value="{x:Null}">
                            <Setter Property="Opacity" TargetName="optionMark" Value="0"/>
                            <Setter Property="Opacity" TargetName="indeterminateMark" Value="1"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

使用方法如下:

<RadioButton Style="{StaticResource CheckBoxRadioButtonStyle}" />

(我只是使用了默认的CheckBox样式并更改了目标类型)

然而,我强烈建议您使用普通的单选按钮,因为用户对此已经很熟悉。互斥的复选框可能会让用户感到奇怪。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接