2009-11-09 2 views
2

Код XAML ниже работает отлично, за исключением того, что кнопка расширения должна находиться между списком и сеткой. Если я установил ExpandDirection = «Влево», кнопка находится между списком и сеткой, но указатель направления на кнопке запутывает пользователей - он указывает на правую, когда расширяется, и указывает слева, когда он не расширяется. Я хочу, чтобы указатель направления работал так, как он работает, когда ExpandDirection = «Right», но мне нужна функциональность ExpandDirection = «Left».Как привязать расширитель к правой стороне ListBox?

<DockPanel> 
    <Expander ExpandDirection="Right"> 
     <ListBox> 
      <ListBoxItem>Item One</ListBoxItem> 
      <ListBoxItem>Item Two</ListBoxItem> 
      <ListBoxItem>Item Three</ListBoxItem> 
      <ListBoxItem>Item Four</ListBoxItem> 
      <ListBoxItem>Item Five</ListBoxItem> 
     </ListBox> 
    </Expander> 
     <Grid Background="AliceBlue"> 
      <TextBlock > 
      Other Content 
      </TextBlock> 
     </Grid> 
</DockPanel> 

ответ

2

Использование Expression Blend, редактировать копию текущего шаблона для Expander, перейдите в XAML для шаблона, переименовать «ExpanderLeftHeaderStyle» в «ExpanderRightHeaderStyle» и «ExpanderRightHeaderStyle» на «ExpanderLeftHeaderStyle».

+0

Это работает, но имеет недостаток в копировании нескольких сотен строк стиля XAML в ваш проект. Это может сделать ваш проект несколько сложнее в обслуживании. У него также есть недостаток, заключающийся в том, чтобы не обрабатывать будущие изменения темы. –

2

Я предпочитаю использовать класс DockedExpander, который я написал некоторое время назад (код приведен ниже). Этот класс автоматически настраивается для любой стороны DockPanel, на которой он закреплен.

Например, в:

<DockPanel> 
    <edf:DockedExpander DockPanel.Dock="Left"> 
    <ListBox ... 
    </edf:DockedExpander> 

    <Grid ... 

</DockPanel> 

расширитель откроется слева, с помощью кнопки, обращенной правильный путь. Но смена его на:

<edf:DockedExpander DockPanel.Dock="Right"> 

будет автоматически регулировать остальную часть расширителя в соответствии с этим. То же самое с стыковкой «Top» и «Bottom».

Я реализовал DockedExpander, потому что мысль о копировании нескольких сотен строк внутреннего кода WPF в мой проект была отвратительной для меня. Кроме того, мой контроллер DockedExpander автоматически адаптируется к новым стилям тем, поскольку он читает внутренние стили WPF.

Вот код класса DockedExpander:

public class DockedExpander : Expander 
{ 
    static DockedExpander() 
    { 
    _directions = new Dictionary<Dock, DirectionData>(); 
    _directions[Dock.Left] = new DirectionData { Reverse = Dock.Right, ExpandDirection = ExpandDirection.Right }; 
    _directions[Dock.Right] = new DirectionData { Reverse = Dock.Left, ExpandDirection = ExpandDirection.Left }; 
    _directions[Dock.Top] = new DirectionData { Reverse = Dock.Bottom, ExpandDirection = ExpandDirection.Down }; 
    _directions[Dock.Bottom] = new DirectionData { Reverse = Dock.Top, ExpandDirection = ExpandDirection.Up }; 

    DockPanel.DockProperty.OverrideMetadata(typeof(DockedExpander), new FrameworkPropertyMetadata 
    { 
     PropertyChangedCallback = (obj, e) => ((DockedExpander)obj).UpdateExpandDirection() 
    }); 

    ExpandDirectionProperty.OverrideMetadata(typeof(DockedExpander), new FrameworkPropertyMetadata 
    { 
     PropertyChangedCallback = (obj, e) => { throw new ArgumentException("Cannot set ExpandDirection because DockedExpander always computes its ExpandDirection from the DockPanel.Dock property"); } 
    }); 
    } 

    public override void OnApplyTemplate() 
    { 
    base.OnApplyTemplate(); 
    UpdateExpandDirection(); 
    } 

    private void UpdateExpandDirection() 
    { 
    // Can't use GetTemplateChild because non-PART_ names are not guaranteed to stay the same 
    var dockPanel = FindTwoElementDockPanelUnder(this); 
    var headerSite = dockPanel.Children[0]; 
    var expandSite = dockPanel.Children[1]; 

    // Compute the docking 
    Dock myDock = DockPanel.GetDock(this); 
    DirectionData myDockData = _directions[myDock]; 

    DockPanel.SetDock(headerSite, myDockData.Reverse); 
    DockPanel.SetDock(expandSite, myDock); 
    headerSite.SetValue(FrameworkElement.StyleProperty, myDockData.HeaderSiteStyle); 
    } 

    private static Dictionary<Dock, DirectionData> _directions; 
    private class DirectionData 
    { 
    public Dock Reverse; 
    public ExpandDirection ExpandDirection; 
    public Style HeaderSiteStyle 
    { 
     get 
     { 
     if(_headerSiteStyle==null) 
     { 
      var expander = new Expander { ExpandDirection = this.ExpandDirection }; 
      expander.BeginInit(); 
      expander.EndInit(); 
      expander.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); 
      var headerSite = FindTwoElementDockPanelUnder(expander).Children[0]; 
      _headerSiteStyle = ((FrameworkElement)headerSite).Style; 
     } 
     return _headerSiteStyle; 
     } 
    } 
    private Style _headerSiteStyle; 
    } 

    private static DockPanel FindTwoElementDockPanelUnder(DependencyObject visual) 
    { 
    while(true) 
     switch(VisualTreeHelper.GetChildrenCount(visual)) 
     { 
     case 1: visual = VisualTreeHelper.GetChild(visual, 0); continue; 
     case 2: return visual as DockPanel; 
     default: return null; 
     } 
    } 
} 

Как обычно, вам нужно объявление пространства имен (Xmlns) в вашем XAML, чтобы иметь возможность использовать пользовательский элемент управления.

Смежные вопросы