代码改变世界

Windows Presentation Foundation(wpf) FAQ

2008-07-06 18:26  Clingingboy  阅读(1850)  评论(0编辑  收藏  举报

     这个帖子在微软官方的wpf讨论区http://forums.msdn.microsoft.com/en-US/wpf/thread/a2988ae8-e7b8-4a62-a34f-b851aaf13886
索性这个帖子是以前在我们博客园的同志sheva发的,不知道为何他建了一个新的bloghttp://shevaspace.blogspot.com/,不知道因为这篇blog的原因http://www.cnblogs.com/sheva/archive/2006/10/03/520583.html。。。。。So,有时间翻译翻译

3. 控件

3.1 如何展开TreeView 的所有节点(TreeViewItems) ?

不像Windows Forms,当前版本的WPF并没有提供以一行代码这样简单的方法来展开TreeView控件的所有节点。

一般而言,有两种方法可以实现这个功能.第一个方法是改变WPF 样式外观。以下xaml展示了这一方法:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Page.Resources>
    <XmlDataProvider x:Key="treeData" XPath="*">
      <x:XData>
        <Items Name="Items" xmlns="">
          <Item1/>
          <Item2>
            <Item22/>
            <Item12/>
            <Item13>
              <Item131/>
              <Item131/>
            </Item13>
          </Item2>
        </Items>
      </x:XData>
    </XmlDataProvider>
    <HierarchicalDataTemplate ItemsSource="{Binding XPath=child::*}"
x:Key="template">
      <TextBlock Name="textBlock" Text="{Binding Name}"/>
    </HierarchicalDataTemplate>
  </Page.Resources>
  <TreeView ItemTemplate="{StaticResource template}"
ItemsSource="{Binding Source={StaticResource treeData}}">
<TreeView.ItemContainerStyle>
      <!--Using style setter to set the TreeViewItem.IsExpanded property to true, this will be applied
      to all TreeViweItems when they are generated-->
      <Style TargetType="{x:Type TreeViewItem}">
        <Setter Property="IsExpanded" Value="True"/>
      </Style>
    </TreeView.ItemContainerStyle>
  </TreeView>
</Page>

有些时候,你需要以编程的方式来实现这一功能,你可以用下面c#的辅助方法来展开所有节点

public static class TreeViewHelper 
{ 
public static void ExpandAll(TreeView treeView) 
    { 
        ExpandSubContainers(treeView); 
    } 
private static void ExpandSubContainers(ItemsControl parentContainer) 
    { 
foreach (Object item in parentContainer.Items) 
        { 
TreeViewItem currentContainer = parentContainer.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem; 
if (currentContainer != null && currentContainer.Items.Count > 0) 
            { 
// Expand the current item. 
                currentContainer.IsExpanded = true; 
if (currentContainer.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) 
                { 
// If the sub containers of current item is not ready, we need to wait until 
// they are generated. 
                    currentContainer.ItemContainerGenerator.StatusChanged += delegate 
                    { 
                        ExpandSubContainers(currentContainer); 
                    }; 
                } 
else 
                { 
// If the sub containers of current item is ready, we can directly go to the next 
// iteration to expand them. 
                    ExpandSubContainers(currentContainer); 
                } 
            } 
        } 
    } 
}

The key to this technique shown above is to make sure that the container for the current TreeViewItem has been generated, so you can safely expand it to show all its sub items. That's why you need to make a recursive call when the status of current TreeViewItem's ItemContainerGenerator is GeneratorStatus.ContainersGenerated.

相关帖子:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2014662&SiteID=1
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3180239&SiteID=1
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1130017&SiteID=1

3.2 如何在ListBox/ListView中实现拖拽?

Lasso selection is used quite often in most graphical editing programs, and it's a convenient way to select multiple on-screen objects. The following shows how to enable this type of selection to the WPF ListBox/ListView controls:

<ListBox Name="listBox"
Width="200"
Height="200"
SelectionMode="Multiple">
  <ListBox.Resources>
    <Style TargetType="{x:Type ListBoxItem}">
      <EventSetter Event="ListBoxItem.PreviewMouseLeftButtonDown"
Handler="ListBoxItem_PreviewMouseLeftButtonDown"/>
      <EventSetter Event="ListBoxItem.PreviewMouseUp"
Handler="ListBoxItem_PreviewMouseUp"/>
      <EventSetter Event="ListBoxItem.PreviewMouseMove"
Handler="ListBoxItem_PreviewMouseMove"/>
    </Style>
  </ListBox.Resources>
  <x:Type TypeName="DependencyObject"/>
  <x:Type TypeName="Visual"/>
  <x:Type TypeName="UIElement"/>
  <x:Type TypeName="FrameworkElement"/>
  <x:Type TypeName="Control"/>
</ListBox> 

 

public partial class Window1 : Window
{
// This field is used to tell if ListBox is in mouse selection mode.
private Boolean inMouseSelectionMode = false;
// This field is used to keep track of the current mouse selected items.
private List<ListBoxItem> selectedItems = new List<ListBoxItem>();
public Window1()
    {
        InitializeComponent();
    }
private void ListBoxItem_PreviewMouseUp(object sender, MouseButtonEventArgs e)
    {
// If the mouse is up, turn off "inMouseSelectionMode"
        inMouseSelectionMode = false;
    }
private void ListBoxItem_PreviewMouseMove(object sender, MouseEventArgs e)
    {
ListBoxItem mouseOverItem = sender as ListBoxItem;
if (mouseOverItem != null && inMouseSelectionMode && e.LeftButton == MouseButtonState.Pressed)
        {
            mouseOverItem.Background = SystemColors.HighlightBrush;
// Highlight the currently mouse-overed item.
            mouseOverItem.SetValue(TextElement.ForegroundProperty, SystemColors.HighlightTextBrush);
if (!selectedItems.Contains(mouseOverItem))
            {
                selectedItems.Add(mouseOverItem);
            }
        }
    }
private void ListBoxItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
// When the mouse is down, we need to clear all previously mouse selected items.
        listBox.SelectedIndex = -1;
        inMouseSelectionMode = true;
foreach (ListBoxItem item in selectedItems)
        {
            item.ClearValue(ListBoxItem.BackgroundProperty);
            item.ClearValue(TextElement.ForegroundProperty);
        }
        selectedItems.Clear();
    }
} 

 

Related threads:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2443181&SiteID=1
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2427163&SiteID=1

3.3 How to implement RadioButtonList type of control in WPF?

WPF doesn't provide RadioButtonList control like ASP.NET does. Fortunately with WPF's powerful styling and templating capability, we could implement this type of control purely in XAML. Here is a XAMLPad ready example:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:System;assembly=mscorlib">
  <Page.Resources>
    <x:Array Type="{x:Type s:String}" x:Key="data">
      <s:String>Option1</s:String>
      <s:String>Option2</s:String>
      <s:String>Option3</s:String>
    </x:Array>
  </Page.Resources>
  <StackPanel DataContext="{StaticResource data}">
    <TextBlock Margin="5">
      <TextBlock Text="Current Option:"/>
      <TextBlock Text="{Binding /}"/>
    </TextBlock>
    <ListBox
ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True"
Width="240"
Height="60"
HorizontalAlignment="Left">
      <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
          <Setter Property="Template">
            <Setter.Value>
              <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <RadioButton
IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource TemplatedParent}}"
Content="{TemplateBinding Content}"/>
              </ControlTemplate>
            </Setter.Value>
          </Setter>
        </Style>
      </ListBox.ItemContainerStyle>
    </ListBox>
  </StackPanel>
</Page> 

Related threads:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3023610&SiteID=1