【问题标题】:Issues with CustomContainer for RadioButtons in WPFWPF 中单选按钮的 CustomContainer 问题
【发布时间】:2009-07-24 10:27:19
【问题描述】:

我想创建一个只包含 RadioButtons 的自定义控件。我想它的用法如下:

<RadioButtonHolder Orientation="Horizontal">
<RadioButton>RadioButton 1</RadioButton>
<RadioButton>RadioButton 2</RadioButton>
<RadioButton>RadioButton 3</RadioButton>
<RadioButton> ...</RadioButton>
</RadioButtonHolder>

目前,我创建了一个自定义控件来部分执行此操作。然而,它似乎保留了 RadioButtons 的持续集合。它会将这个 RadioButtons 集合添加到最后一个初始化的控件中。有谁知道为什么会这样?非常感谢任何帮助。

编辑: 我有点明白这里面发生了什么。似乎在初始化对象时,它会创建一个RadioButtons 列表,其中包含所有 RadioButtons,然后它将作为子项附加到窗口中的所有RadioButtonHolder 控件。最后一个控件开始显示项目。

但是我不确定如何防止这种情况,只能将内容本地化到每个控件。所以如果我写:

<RadioButtonHolder Name="RBH1">
<RadioButton Name="RB1">RB 1</RadioButton>
<RadioButton Name="RB2">RB 2</RadioButton>
</RadioButtonHolder>
<RadioButtonHolder Name="RBH2">
<RadioButton Name="RB3">RB 3</RadioButton>
<RadioButton Name="RB4">RB 4</RadioButton>
</RadioButtonHolder>

RB1 & RB2 将在RBH1 中显示,RB3 & RB4 将在RBH2 中显示为子项。

我的代码如下:

CustomControl.cs

using System.Collections.Generic;
using System.Windows;
using Sytem.Windows.Controls;
using System.Windows.Markup;

namespace RandomControl
{
[ContentProperty("Children")]
public class CustomControl1 : Control
{
   public static DependencyProperty ChildrenProperty = 
      DependencyProperty.Register("Children", typeof(List<RadioButton>),
      typeof(CustomControl1),new PropertyMetadata(new List<RadioButton>()));

   public List<RadioButton> Children
   {
       get { return (List<RadioButton>)GetValue(ChildrenProperty); }
       set { SetValue(ChildrenProperty, value); }
   }

    static CustomControl1()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), 
             new FrameworkPropertyMetadata(typeof(CustomControl1)));
    }
 }
}

Generic.xaml

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:RandomControl">
 <Style TargetType="{x:Type local:CustomControl1}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:CustomControl1}">
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <ItemsControl ItemsSource="{TemplateBinding Children}" 
                      Background="{TemplateBinding Background}">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel></StackPanel>
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                    </ItemsControl>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
 </Style>
</ResourceDictionary>

【问题讨论】:

    标签: wpf-controls custom-controls radio-button


    【解决方案1】:

    WPF 旨在尽可能简单地使用,但它也是非常新的,一开始并不那么容易上手。

    你只需要一个像这样的 xaml:

    在你的窗口/页面/用户控件中添加资源

    <Style x:Key="rbStyle" TargetType="RadioButton">
        <!--modify style to fit your needs-->
        <Setter Property="Margin" Value="2"/>
    </Style>
    
    <Style x:Key="rbStackPanelStyle" TargetType="StackPanel">
        <!--modify style to fit your needs-->
        <Setter Property="Orientation" Value="Vertical"/>
        <Setter Property="Margin" Value="2"/>
    </Style>
    

    然后在需要的地方声明你的“radioButtonHolder”:

    <StackPanel x:Name="rbHolder1" Style="{StaticResource rbStackPanelStyle}">
        <RadioButton Style="{StaticResource rbStyle}">RadioButton 1</RadioButton>
        <RadioButton Style="{StaticResource rbStyle}">RadioButton 2</RadioButton>
        <RadioButton Style="{StaticResource rbStyle}">RadioButton 3</RadioButton>
        <RadioButton Style="{StaticResource rbStyle}">...</RadioButton>
    </StackPanel>
    

    根据您的问题,这应该符合您的需求。不需要自定义控件。并且许多进一步的修改可以适合其中的样式和模板。

    希望这有帮助,干杯。

    【讨论】:

    • 谢谢! :) 这样做确实有意义。不过,最初我想让持有者做的是在 RadioButtons 上覆盖一个 InkPresenter,这样我就可以进行一些花哨的笔交互。
    【解决方案2】:

    我刚刚发现我做错了什么!它就在我面前,我没看到。

    这个问题的问题在于我将 Children 设置为 DependencyProperty - 这意味着它将是静态的和全局的。所以整个RadioButton 集合几乎可用于Window 中的所有控件。 (事后看来,这可能是 StackPanel、Canvas 等没有 Children 属性作为 DependencyProperty 的原因)。 您可以找到有关此here 的更多信息。

    感谢 kek444 发布了一种更简单的方法。 :D

    为了解决这个问题,您需要删除 DependencyProperty 并将 Children 声明为具有私有 set 的普通属性。

    我已经修改了代码:

    CustomControl.cs

    using System.Collections.Generic;
    using System.Windows;
    using Sytem.Windows.Controls;
    using System.Windows.Markup;
    
    namespace RandomControl
    {
        [ContentProperty("Children")]
        public class CustomControl1 : Control
        {
            private ObservableCollection<RadioButton> _children;
            private ItemsControl _control;
    
            public ObservableCollection<RadioButton> Children
            {
                get
                {
                    if (_children == null)
                        _children = new ObservableCollection<RadioButton>();
                    return _children;
                }
                private set { _children = value; }
            }
    
            static CustomControl1()
            {
                DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), 
                 new FrameworkPropertyMetadata(typeof(CustomControl1)));
            }
    
            public override void OnApplyTemplate()
            {
                base.OnApplyTemplate();
    
                _control = base.GetTemplateChild("PART_ItemsControl") 
                                as ItemsControl;
    
                // display the radio buttons
                if (_control != null)
                    _control.ItemsSource = Children;
            }
        }
    }
    

    Generic.xaml

    <ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:RandomControl">
     <Style TargetType="{x:Type local:CustomControl1}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:CustomControl1}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <ItemsControl Name="PART_ItemControl"  
                          Background="{TemplateBinding Background}">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <StackPanel></StackPanel>
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                        </ItemsControl>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
     </Style>
    </ResourceDictionary>
    

    【讨论】:

      猜你喜欢
      • 2014-06-19
      • 1970-01-01
      • 2018-09-12
      • 2016-03-02
      • 1970-01-01
      • 1970-01-01
      • 2014-12-30
      • 1970-01-01
      相关资源
      最近更新 更多