繁体   English   中英

自定义项目控制和选择支持

[英]Custom ItemsControl and selection support

我想创建一个控件:

  • 从ItemsControl派生,
  • 可以绑定到枚举列表,
  • 对于每个枚举,它将显示RadioButton,
  • 如果选择给定的RadioButton,则SelectedItem将包含与RadioButton关联的枚举值。

我已经设法实现了上面列表中的前三点,但是我对第四项有疑问。 我怀疑它可能与项目容器类的错误实现或generic.xaml中的项目模板定义错误有关。

物料容器如下所示:

public class MyEnumSelectorItem : ContentControl
{
public static readonly DependencyProperty IsSelectedProperty;

static MyEnumSelectorItem()
{
    IsSelectedProperty = Selector.IsSelectedProperty.AddOwner(typeof(MyEnumSelectorItem));
}

public bool IsSelected
{
    get { return (bool)GetValue(IsSelectedProperty); }
    set { SetValue(IsSelectedProperty, value); }
}

static readonly DependencyProperty ModeProperty = 
    DependencyProperty.Register("Mode", typeof(MyEnum), typeof(MyEnumSelector), new PropertyMetadata());
public MyEnum Mode
{
    get { return (MyEnum)GetValue(ModeProperty); }
    set { SetValue(ModeProperty, value); }
}
}

使用IsItemItsOwnContainerOverride/GetContainerForItemOverride/PrepareContainerForItemOverride方法重写,将项目容器类型与选择器控件(从System.Windows.Controls.Primitives.Selector派生)相关联。

generic.xaml的相关片段如下所示:

<Style TargetType="{x:Type controls:MyEnumSelector}">
    <Setter Property="ItemTemplate">
        <Setter.Value>
            <DataTemplate>
                <RadioButton Content="{Binding}" 
                     IsChecked="{Binding IsSelected, Mode=TwoWay}" 
                     GroupName="enumSelector" Height="25" FontWeight="Bold"  />
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

上面假设IsSelected属性的正确绑定将自动导致设置SelectedItem属性(我希望是正确的,不是吗?)。

在我看来,仅在此处调用Selector.IsSelectedProperty.AddOwner是不够的。

查看ILSpyListBoxItem的代码,您可以看到可能在完成其他一些事情以在选定项和选择器本身之间进行同步,例如引发Selected / Unselected事件。

static ListBoxItem()
{
    ListBoxItem.IsSelectedProperty = Selector.IsSelectedProperty.AddOwner(typeof(ListBoxItem), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal, new PropertyChangedCallback(ListBoxItem.OnIsSelectedChanged)));
    ListBoxItem.SelectedEvent = Selector.SelectedEvent.AddOwner(typeof(ListBoxItem));
    ListBoxItem.UnselectedEvent = Selector.UnselectedEvent.AddOwner(typeof(ListBoxItem));
    ...
}

private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    ListBoxItem listBoxItem = d as ListBoxItem;
    bool flag = (bool)e.NewValue;
    Selector parentSelector = listBoxItem.ParentSelector;
    if (parentSelector != null)
    {
        parentSelector.RaiseIsSelectedChangedAutomationEvent(listBoxItem, flag);
    }
    if (flag)
    {
        listBoxItem.OnSelected(new RoutedEventArgs(Selector.SelectedEvent, listBoxItem));
    }
    else
    {
        listBoxItem.OnUnselected(new RoutedEventArgs(Selector.UnselectedEvent, listBoxItem));
    }
    listBoxItem.UpdateVisualState();
}

我自己没有尝试过看看是否能真正解决问题,但我认为这是一个不错的起点。 您还应该考虑让项目从ListBoxItem而不是ContentControl派生。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM