[英]How to add checkboxes on TreeView
我是 C# 和 WPF 的新手,我想構建一個可以選擇文件夾和文件並獲取路徑的應用程序。 按照此鏈接中的說明,我能夠顯示文件夾結構並添加一個復選框。
但我不確定如何實現這一目標。
下面是我的代碼。
WPF
<TreeView Name="MyTreeView" Margin="249,31,20,24" Background="{x:Null}" BorderThickness="0,0,0,0" Cursor="Arrow">
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Name="MyCheckBox"/>
<Image Name="img" Width="20" Height="20" Stretch="Fill"
Source="{Binding RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType={x:Type TreeViewItem}},
Path=Tag,
Converter={x:Static local:TagToImageConverter.Instance}}"/>
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.Resources>
</TreeView>
C#
// Get users' folders
private void GetUsersFolder_Loaded(object sender, RoutedEventArgs e)
{
foreach (string s in Directory.GetDirectories("C:\\Users") )
{
if (!s.Contains("All Users") && !s.Contains("Default") && !s.Contains("Default User") && !s.Contains("Public"))
{
TreeViewItem user_folders = new TreeViewItem();
user_folders.Header = s.Substring(s.LastIndexOf("\\") + 1);
user_folders.Tag = new object[] { PrjRootPath+"icons\\mainpage\\folder.png", s };
user_folders.FontWeight = FontWeights.Normal;
user_folders.FontSize = 14;
user_folders.Items.Add(dummyNode);
user_folders.Expanded += new RoutedEventHandler(Userfolders_Expanded);
MyTreeView.Items.Add(user_folders);
}
}
}
// Get folders inside user's folder
void Userfolders_Expanded(object sender, RoutedEventArgs e)
{
TreeViewItem item = (TreeViewItem)sender;
if (item.Items.Count == 1 && item.Items[0] == dummyNode)
{
item.Items.Clear();
try
{
foreach (string s in Directory.GetDirectories(((Object[])item.Tag)[1].ToString()))
{
if (s.Contains("Desktop") ||
s.Contains("Documents") ||
s.Contains("Downloads") ||
s.Contains("Pictures") ||
s.Contains("Contacts") ||
s.Contains("Videos"))
{
TreeViewItem subitem = new TreeViewItem();
subitem.Header = s.Substring(s.LastIndexOf("\\") + 1);
subitem.Tag = new object[] { PrjRootPath + "icons\\mainpage\\folder.png", s };
subitem.FontWeight = FontWeights.Normal;
subitem.Items.Add(dummyNode);
subitem.Expanded += new RoutedEventHandler(InsideUserfoldersFiles_Expanded);
item.Items.Add(subitem);
}
}
}
catch (Exception e1) { MessageBox.Show(e1.Message + " " + e1.InnerException); }
}
}
// Get folders and files inside the folders of user's folder
void InsideUserfoldersFiles_Expanded(object sender, RoutedEventArgs e)
{
TreeViewItem item = (TreeViewItem)sender;
if (item.Items.Count == 1 && item.Items[0] == dummyNode)
{
item.Items.Clear();
try
{
foreach (string s in Directory.GetDirectories(((Object[])item.Tag)[1].ToString()))
{
TreeViewItem subitem = new TreeViewItem();
subitem.Header = s.Substring(s.LastIndexOf("\\") + 1);
subitem.Tag = new object[] { PrjRootPath + "icons\\mainpage\\folder.png", s };
subitem.FontWeight = FontWeights.Normal;
subitem.Items.Add(dummyNode);
subitem.Expanded += new RoutedEventHandler(InsideUserfoldersFiles_Expanded);
item.Items.Add(subitem);
}
foreach (string s in Directory.GetFiles(((Object[])item.Tag)[1].ToString()))
{
string f_extention = s.Substring(s.LastIndexOf(".") + 1);
if (f_extention != "ini" && f_extention != "lnk")
{
String f_type = PrjRootPath + "icons\\mainpage\\file.png";
if (s.Contains(".csv") ||
s.Contains(".xlsx") ||
s.Contains(".xlsm") ||
s.Contains(".xls"))
{
f_type = PrjRootPath + "icons\\mainpage\\excel.png";
}
else if (s.Contains(".docx") ||
s.Contains(".doc") ||
s.Contains(".docm") ||
s.Contains(".dotm"))
{
f_type = PrjRootPath + "icons\\mainpage\\word.png";
}
else if (s.Contains(".pptx") ||
s.Contains(".pptm") ||
s.Contains(".ppt") ||
s.Contains(".potm"))
{
f_type = PrjRootPath + "icons\\mainpage\\powerpoint.png";
}
else if (s.Contains(".msg"))
{
f_type = PrjRootPath + "icons\\mainpage\\outlook.png";
}
else if (s.Contains(".pdf"))
{
f_type = PrjRootPath + "icons\\mainpage\\pdf.png";
}
else if (s.Contains(".png"))
{
f_type = PrjRootPath + "icons\\mainpage\\image.png";
}
else
{
f_type = PrjRootPath + "icons\\mainpage\\file.png";
}
TreeViewItem subitem = new TreeViewItem();
subitem.Header = s.Substring(s.LastIndexOf("\\") + 1);
subitem.Tag = new object[] { f_type, s };
subitem.FontWeight = FontWeights.Normal;
item.Items.Add(subitem);
}
}
}
catch (Exception e2) { MessageBox.Show(e2.Message + " " + e2.InnerException); }
}
}
你們可以給我一些例子嗎? 太感謝了!
首先,您當前沒有按照設計使用的方式使用 WPF。 具體來說,您正在手動創建樹元素,而不是使用數據綁定。 現在這又回來咬你了,如果你繼續沿着你走的路走下去,情況只會變得更糟。
無論哪種方式,您需要在這里做的是將復選框控件模板化,以便您可以更改刻度圖形。 如果您在 XAML 代碼中的任何位置添加 CheckBox,請將光標放在它上面,然后在右側的“屬性”面板中選擇 Miscellaneous -> Template -> Convert to New Resource,您將獲得一個完全展開的 CheckBox 模板(例如“CheckBoxTemplate1”),然后您可以將其分配給 TreeView 數據模板中的 CheckBox:
<StackPanel Orientation="Horizontal">
<CheckBox Name="MyCheckBox" Template="{DynamicResource CheckBoxTemplate1}"/>
查看模板本身,您會看到負責其圖形外觀的所有位,包括:
<Grid x:Name="markGrid">
<Path x:Name="optionMark" Data="F1 M 9.97498,1.22334L 4.6983,9.09834L 4.52164,9.09834L 0,5.19331L 1.27664,3.52165L 4.255,6.08833L 8.33331,1.52588e-005L 9.97498,1.22334 Z " Fill="{StaticResource OptionMark.Static.Glyph}" Margin="1" Opacity="0" Stretch="None"/>
<Rectangle x:Name="indeterminateMark" Fill="{StaticResource OptionMark.Static.Glyph}" Margin="2" Opacity="0"/>
“optionMark”元素負責勾選,因此您可以通過簡單地更改路徑標記將其變成矩形:
<Path x:Name="optionMark" Data="M 0,0L 10,0L 10,10L 0,10L 0,0 Z " Fill="{StaticResource OptionMark.Static.Glyph}" Margin="1" Opacity="0" Stretch="None"/>
結果:
現在看來您只希望將其應用於文件夾,而不是文件,這就是它變得棘手的地方。 您的模板代碼需要一種方法來區分您傳遞給它的兩種類型的數據(即文件夾與文件)。 添加它的唯一地方是作為 subitem.Tag 數組中的第三個元素......現在已經變得非常混亂......並使用 DataTemplate 選擇要渲染的路徑,即如下所示:
<Path x:Name="optionMark" Fill="{StaticResource OptionMark.Static.Glyph}" Margin="1" Opacity="0" Stretch="None">
<Path.Style>
<Style TargetType="Path">
<Setter Property="Data" Value="F1 M 9.97498,1.22334L 4.6983,9.09834L 4.52164,9.09834L 0,5.19331L 1.27664,3.52165L 4.255,6.08833L 8.33331,1.52588e-005L 9.97498,1.22334 Z" />
<Style.Triggers>
<DataTrigger Binding="{RelativeSource={RelativeSource AncestorType=TreeViewItem}, Path=Tag[2]}" Value="True">
<Setter Property="Data" Value="M 0,0L 10,0L 10,10L 0,10L 0,0 Z" />
</DataTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
順便說一句,不要將 DataTrigger 綁定視為逐字記錄,我還沒有對其進行測試,但是您明白了……您必須在標簽中使用一個元素來告訴 Path 要使用哪些數據。
還有其他方法可以做到這一點,例如,當您創建 TreeViewItem 時,您可以在那里為其分配新的 ControlTemplate,您必須從資源塊中加載它。 但老實說,這只會變得更糟。 您最好的選擇,IMO,是從模板中取出 DataTrigger 並按照它的預期使用方式使用 TreeView,即為您嘗試繪制的每種類型的對象創建數據結構:
public FolderViewModel[] Items { get; } = {
new FolderViewModel(), new FolderViewModel(), new FolderViewModel(),
};
public class FolderViewModel : FileViewModel
{
public FileViewModel[] Children{ get; } = {
new FileViewModel(),
new FileViewModel(),
new FileViewModel()
};
public FolderViewModel() : base("Folder") { }
}
public class FileViewModel
{
public string Text { get; set; }
public FileViewModel(string text = "File") => this.Text = text;
}
然后將 Items 分配(或綁定)到您的頂級節點,並根據對象的類型設置 DataTemplate 和 HierarchicalDataTemplate:
<TreeView Name="MyTreeView" Margin="249,31,20,24" Background="{x:Null}" BorderThickness="0,0,0,0" Cursor="Arrow" ItemsSource="{Binding Items}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:FolderViewModel}" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<CheckBox Name="MyCheckBox" Template="{DynamicResource CheckBoxTemplate1}"></CheckBox>
<TextBlock Text="{Binding Text}"/>
</StackPanel>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:FileViewModel}">
<StackPanel Orientation="Horizontal">
<CheckBox Name="MyCheckBox"></CheckBox>
<TextBlock Text="{Binding Text}"/>
</StackPanel>
</DataTemplate>
</TreeView.Resources>
</TreeView>
就是這樣。 文件將使用帶有勾選的默認復選框模板,而文件夾將被分配新模板並獲得一個框。
結果:
xaml 中的以下代碼可以提供幫助
<Window.Resources>
<ResourceDictionary>
<HierarchicalDataTemplate x:Key="CheckBoxItemTemplate" ItemsSource="{Binding Children, Mode=OneTime}">
<StackPanel Orientation="Horizontal">
<CheckBox Focusable="False" IsChecked="{Binding IsChecked}" VerticalAlignment="Center" />
<ContentPresenter Content="{Binding Name, Mode=OneTime}" Margin="2,0" />
</StackPanel>
</HierarchicalDataTemplate>
</ResourceDictionary>
</Window.Resources>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.