有没有一种方法可以模板化 RadioButton,使其具有 TabItem 样式

发布于 2024-10-10 04:26:41 字数 897 浏览 8 评论 0原文

我已经尝试过:

<UniformGrid DockPanel.Dock="Top" Columns="2" Rows="1">
  <UniformGrid.Resources>   
    <Style TargetType="RadioButton">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="RadioButton">
            <TabItem IsSelected="{TemplateBinding IsChecked}">
              <TabItem.Header>
                <ContentPresenter Margin="5" />
              </TabItem.Header>                  
            </TabItem>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
  </UniformGrid.Resources>
  <RadioButton Content="By company name" />
  <RadioButton Content="By contact name" Grid.Column="1"/>
</UniformGrid>

它实际上有效,只是它没有选择/取消选择适当的选项卡。
我当然更喜欢单选按钮,但我的客户坚持认为它应该是选项卡。

I've tried:

<UniformGrid DockPanel.Dock="Top" Columns="2" Rows="1">
  <UniformGrid.Resources>   
    <Style TargetType="RadioButton">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="RadioButton">
            <TabItem IsSelected="{TemplateBinding IsChecked}">
              <TabItem.Header>
                <ContentPresenter Margin="5" />
              </TabItem.Header>                  
            </TabItem>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
  </UniformGrid.Resources>
  <RadioButton Content="By company name" />
  <RadioButton Content="By contact name" Grid.Column="1"/>
</UniformGrid>

It actually works except it doesn't select/unselect the appropriate tab.
I would prefer RadioButtons of course, but my customer insist it should be Tabs.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小巷里的女流氓 2024-10-17 04:26:41

我认为问题在于 TabItem 正在“吃掉”鼠标单击,因此 RadioButton 永远不会被选中/取消选中。您可以将 TabItem 包裹在 Border 中并设置 IsHitTestVisible="False"。这样做您将丢失 IsMouseOver 触发器等,因此您必须从默认模板中重新添加它们

尝试像这样的

<LinearGradientBrush x:Key="TabItemHotBackground" EndPoint="0,1" StartPoint="0,0">
    <GradientStop Color="#EAF6FD" Offset="0.15"/>
    <GradientStop Color="#D9F0FC" Offset=".5"/>
    <GradientStop Color="#BEE6FD" Offset=".5"/>
    <GradientStop Color="#A7D9F5" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="TabItemSelectedBackground" Color="#F9F9F9"/>
<SolidColorBrush x:Key="TabItemHotBorderBrush" Color="#3C7FB1"/>

<Style x:Key="RadioButtonStyle1" TargetType="{x:Type RadioButton}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="RadioButton">
                <Border BorderBrush="Transparent" BorderThickness="0" Background="Transparent" CornerRadius="0">
                    <TabItem x:Name="tabItem" IsSelected="{TemplateBinding IsChecked}" IsHitTestVisible="False">
                        <TabItem.Header>
                            <ContentPresenter Margin="5"/>
                        </TabItem.Header>
                    </TabItem>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="true">
                        <Setter Property="Background" TargetName="tabItem" Value="{StaticResource TabItemHotBackground}"/>
                    </Trigger>
                    <Trigger Property="IsChecked" Value="true">
                        <Setter Property="Panel.ZIndex" Value="1"/>
                        <Setter Property="Background" TargetName="tabItem" Value="{StaticResource TabItemSelectedBackground}"/>
                    </Trigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsChecked" Value="false"/>
                            <Condition Property="IsMouseOver" Value="true"/>
                        </MultiTrigger.Conditions>
                        <Setter Property="BorderBrush" TargetName="tabItem" Value="{StaticResource TabItemHotBorderBrush}"/>
                    </MultiTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

更新

<ControlTemplate TargetType="RadioButton">
    <Border BorderBrush="Transparent" BorderThickness="0" Background="Transparent" CornerRadius="0">
        <TabItem x:Name="tabItem" IsSelected="{TemplateBinding IsChecked}" IsHitTestVisible="False">
            <TabItem.Header>
                <ContentPresenter Margin="5"/>
            </TabItem.Header>
        </TabItem>
    </Border>
</ControlTemplate>

更新2
您可以使用附加行为在单击 TabItem 时引发 RadioButton 上的 MouseDown 事件。或者,您可以只设置 IsChecked="True" 而不是引发点击事件

<ControlTemplate TargetType="RadioButton">
    <TabItem x:Name="tabItem" IsSelected="{TemplateBinding IsChecked}"
             local:LinkWithRadioButtonBehavior.LinkWithRadioButton="True">
        <TabItem.Header>
            <ContentPresenter Margin="5"/>
        </TabItem.Header>
    </TabItem>
</ControlTemplate>

LinkWithRadioButtonBehavior

public static class LinkWithRadioButtonBehavior 
{
    public static readonly DependencyProperty LinkWithRadioButtonProperty = 
        DependencyProperty.RegisterAttached 
        (
            "LinkWithRadioButton", 
            typeof(bool),
            typeof(LinkWithRadioButtonBehavior),
            new UIPropertyMetadata(false, OnLinkWithRadioButtonPropertyChanged) 
        );
    public static bool GetLinkWithRadioButton(DependencyObject obj) 
    {
        return (bool)obj.GetValue(LinkWithRadioButtonProperty); 
    }
    public static void SetLinkWithRadioButton(DependencyObject obj, bool value) 
    {
        obj.SetValue(LinkWithRadioButtonProperty, value); 
    }
    private static void OnLinkWithRadioButtonPropertyChanged(DependencyObject dpo, 
                                                             DependencyPropertyChangedEventArgs e) 
    {
        Control control = dpo as Control;
        if (control != null) 
        { 
            if ((bool)e.NewValue == true) 
            {
                control.PreviewMouseDown += OnMouseDown; 
            } 
            else 
            {
                control.PreviewMouseDown -= OnMouseDown; 
            } 
        } 
    }
    static void OnMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        Control control = sender as Control;
        MouseButtonEventArgs routedEventArgs = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left);
        routedEventArgs.RoutedEvent = RadioButton.MouseDownEvent;
        routedEventArgs.Source = control;
        RadioButton clickedRadioButton = GetVisualParent<RadioButton>(control);
        clickedRadioButton.RaiseEvent(routedEventArgs);
    }
    public static T GetVisualParent<T>(object childObject) where T : Visual
    {
        DependencyObject child = childObject as DependencyObject;
        while ((child != null) && !(child is T))
        {
            child = VisualTreeHelper.GetParent(child);
        }
        return child as T;
    }
}

I think the problem is that the TabItem is "eating" the mouseclick so the RadioButton never gets checked/unchecked. You could wrap the TabItem in a Border and set IsHitTestVisible="False". Doing this you'll lose the IsMouseOver trigger etc, so you'll have to re-add them from the Default template

Try something like this

<LinearGradientBrush x:Key="TabItemHotBackground" EndPoint="0,1" StartPoint="0,0">
    <GradientStop Color="#EAF6FD" Offset="0.15"/>
    <GradientStop Color="#D9F0FC" Offset=".5"/>
    <GradientStop Color="#BEE6FD" Offset=".5"/>
    <GradientStop Color="#A7D9F5" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="TabItemSelectedBackground" Color="#F9F9F9"/>
<SolidColorBrush x:Key="TabItemHotBorderBrush" Color="#3C7FB1"/>

<Style x:Key="RadioButtonStyle1" TargetType="{x:Type RadioButton}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="RadioButton">
                <Border BorderBrush="Transparent" BorderThickness="0" Background="Transparent" CornerRadius="0">
                    <TabItem x:Name="tabItem" IsSelected="{TemplateBinding IsChecked}" IsHitTestVisible="False">
                        <TabItem.Header>
                            <ContentPresenter Margin="5"/>
                        </TabItem.Header>
                    </TabItem>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="true">
                        <Setter Property="Background" TargetName="tabItem" Value="{StaticResource TabItemHotBackground}"/>
                    </Trigger>
                    <Trigger Property="IsChecked" Value="true">
                        <Setter Property="Panel.ZIndex" Value="1"/>
                        <Setter Property="Background" TargetName="tabItem" Value="{StaticResource TabItemSelectedBackground}"/>
                    </Trigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsChecked" Value="false"/>
                            <Condition Property="IsMouseOver" Value="true"/>
                        </MultiTrigger.Conditions>
                        <Setter Property="BorderBrush" TargetName="tabItem" Value="{StaticResource TabItemHotBorderBrush}"/>
                    </MultiTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Update

<ControlTemplate TargetType="RadioButton">
    <Border BorderBrush="Transparent" BorderThickness="0" Background="Transparent" CornerRadius="0">
        <TabItem x:Name="tabItem" IsSelected="{TemplateBinding IsChecked}" IsHitTestVisible="False">
            <TabItem.Header>
                <ContentPresenter Margin="5"/>
            </TabItem.Header>
        </TabItem>
    </Border>
</ControlTemplate>

Update 2
You could use an Attached Behavior to raise the MouseDown event on the RadioButton when the TabItem gets clicked. Alternatively you could just set IsChecked="True" instead of raising the click-event

<ControlTemplate TargetType="RadioButton">
    <TabItem x:Name="tabItem" IsSelected="{TemplateBinding IsChecked}"
             local:LinkWithRadioButtonBehavior.LinkWithRadioButton="True">
        <TabItem.Header>
            <ContentPresenter Margin="5"/>
        </TabItem.Header>
    </TabItem>
</ControlTemplate>

LinkWithRadioButtonBehavior

public static class LinkWithRadioButtonBehavior 
{
    public static readonly DependencyProperty LinkWithRadioButtonProperty = 
        DependencyProperty.RegisterAttached 
        (
            "LinkWithRadioButton", 
            typeof(bool),
            typeof(LinkWithRadioButtonBehavior),
            new UIPropertyMetadata(false, OnLinkWithRadioButtonPropertyChanged) 
        );
    public static bool GetLinkWithRadioButton(DependencyObject obj) 
    {
        return (bool)obj.GetValue(LinkWithRadioButtonProperty); 
    }
    public static void SetLinkWithRadioButton(DependencyObject obj, bool value) 
    {
        obj.SetValue(LinkWithRadioButtonProperty, value); 
    }
    private static void OnLinkWithRadioButtonPropertyChanged(DependencyObject dpo, 
                                                             DependencyPropertyChangedEventArgs e) 
    {
        Control control = dpo as Control;
        if (control != null) 
        { 
            if ((bool)e.NewValue == true) 
            {
                control.PreviewMouseDown += OnMouseDown; 
            } 
            else 
            {
                control.PreviewMouseDown -= OnMouseDown; 
            } 
        } 
    }
    static void OnMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        Control control = sender as Control;
        MouseButtonEventArgs routedEventArgs = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left);
        routedEventArgs.RoutedEvent = RadioButton.MouseDownEvent;
        routedEventArgs.Source = control;
        RadioButton clickedRadioButton = GetVisualParent<RadioButton>(control);
        clickedRadioButton.RaiseEvent(routedEventArgs);
    }
    public static T GetVisualParent<T>(object childObject) where T : Visual
    {
        DependencyObject child = childObject as DependencyObject;
        while ((child != null) && !(child is T))
        {
            child = VisualTreeHelper.GetParent(child);
        }
        return child as T;
    }
}
携君以终年 2024-10-17 04:26:41

您可以将单选按钮设置为切换按钮,并创建分配给“单击”事件混合交互触发器的互斥状态。这很痛苦,但比您接受的答案要少得多。希望它可以帮助某人

You could just style the radiobuttons as ToggleButtons and create mutually exclusive states assigned to the "Click" event Blend Interaction Triggers. It's a pain, but much less so than the answer you accepted. Hope it helps someone

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文