2012-09-09 57 views
2

我想创建一个控制:自定义的ItemsControl和选择支持

  • 自ItemsControl派生,
  • 可以绑定到枚举的列表,
  • 每个枚举它会显示单选按钮,
  • 当选中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属性进行设置(我希望是正确的,不是吗?)。

+0

你不应该从'Selector'派生吗? 'SelectedItem'在'Selector'上定义,而不是'ItemsControl'。 –

+0

实际上它来自Selector(稍后在我的问题中指出) - 在第一句中,我的意思是它应该至少从ItemsControl派生。 –

回答

1

在我看来,只是打电话Selector.IsSelectedProperty.AddOwner是不够的。

ILSpy看着ListBoxItem的代码,你可以看到其他一些事情可能正在做的选择商品和选择自身之间同步,就像养选定/未选定的事件。

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

+0

刚才我试着从ListBoxItem派生MyEnumSelectorItem,并且(作为一个单独的尝试)添加OnIsSelectedChanged回调 - 不幸的是没有改变(并且回调没有被调用)。 –

+0

@TomaszGrobelny如果未调用回调(并且您记得将其添加到属性的元数据中),那么很有可能您的绑定有问题。您应该查找绑定错误并确保实际设置值。 –

+0

是的,它被添加到属性元数据,就像上面一样。我只在VS的输出窗口中发现了以下错误:System.Windows.Data错误:39:BindingExpression路径错误:在'object''''MyEnum'(HashCode = 4)'找不到'IsSelected'属性。 BindingExpression:路径= IsSelected; DataItem ='MyEnum'(HashCode = 4);目标元素是'RadioButton'(Name ='');目标属性是'IsChecked'(类型'Nullable'1') 看来我的绑定是指原始枚举而不是容器项目(它是作为调试器显示的创建的)...但是,我如何编写正确的绑定? –