mirror of
https://gitcode.com/gh_mirrors/se/Semi.Avalonia
synced 2026-04-06 17:26:34 +08:00
misc: transfer TreeDataGrid demo.
This commit is contained in:
@@ -39,8 +39,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Semi.Avalonia.Demo.Drm", "d
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Semi.Avalonia.TreeDataGrid", "src\Semi.Avalonia.TreeDataGrid\Semi.Avalonia.TreeDataGrid.csproj", "{398D2998-0835-41F5-99A3-608CAB8051E2}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Semi.Avalonia.TreeDataGrid", "src\Semi.Avalonia.TreeDataGrid\Semi.Avalonia.TreeDataGrid.csproj", "{398D2998-0835-41F5-99A3-608CAB8051E2}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Semi.Avalonia.TreeDataGrid.Demo", "demo\Semi.Avalonia.TreeDataGrid.Demo\Semi.Avalonia.TreeDataGrid.Demo.csproj", "{6178B545-4BB6-458C-A27C-EE11F3885D38}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -84,10 +82,6 @@ Global
|
|||||||
{398D2998-0835-41F5-99A3-608CAB8051E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{398D2998-0835-41F5-99A3-608CAB8051E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{398D2998-0835-41F5-99A3-608CAB8051E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{398D2998-0835-41F5-99A3-608CAB8051E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{398D2998-0835-41F5-99A3-608CAB8051E2}.Release|Any CPU.Build.0 = Release|Any CPU
|
{398D2998-0835-41F5-99A3-608CAB8051E2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{6178B545-4BB6-458C-A27C-EE11F3885D38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{6178B545-4BB6-458C-A27C-EE11F3885D38}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{6178B545-4BB6-458C-A27C-EE11F3885D38}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{6178B545-4BB6-458C-A27C-EE11F3885D38}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -98,7 +92,6 @@ Global
|
|||||||
{D789AEDB-EBDF-4450-8E8E-B4A03FB257B0} = {43091528-9509-43CB-A003-9C5C11E96DD6}
|
{D789AEDB-EBDF-4450-8E8E-B4A03FB257B0} = {43091528-9509-43CB-A003-9C5C11E96DD6}
|
||||||
{0C81FC1C-5D2D-478A-9876-923A0C85EC2F} = {43091528-9509-43CB-A003-9C5C11E96DD6}
|
{0C81FC1C-5D2D-478A-9876-923A0C85EC2F} = {43091528-9509-43CB-A003-9C5C11E96DD6}
|
||||||
{86D93406-412A-4429-93B2-92AAD0407784} = {43091528-9509-43CB-A003-9C5C11E96DD6}
|
{86D93406-412A-4429-93B2-92AAD0407784} = {43091528-9509-43CB-A003-9C5C11E96DD6}
|
||||||
{6178B545-4BB6-458C-A27C-EE11F3885D38} = {43091528-9509-43CB-A003-9C5C11E96DD6}
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {7CA41ED3-2CED-40CC-AA21-28C3B42B1E86}
|
SolutionGuid = {7CA41ED3-2CED-40CC-AA21-28C3B42B1E86}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
<semi:SemiPopupAnimations />
|
<semi:SemiPopupAnimations />
|
||||||
<StyleInclude Source="avares://Semi.Avalonia.DataGrid/Index.axaml" />
|
<StyleInclude Source="avares://Semi.Avalonia.DataGrid/Index.axaml" />
|
||||||
<StyleInclude Source="avares://Semi.Avalonia.ColorPicker/Index.axaml" />
|
<StyleInclude Source="avares://Semi.Avalonia.ColorPicker/Index.axaml" />
|
||||||
|
<StyleInclude Source="avares://Semi.Avalonia.TreeDataGrid/Index.axaml" />
|
||||||
</Application.Styles>
|
</Application.Styles>
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using Avalonia;
|
|||||||
using Avalonia.Data.Converters;
|
using Avalonia.Data.Converters;
|
||||||
using Avalonia.Metadata;
|
using Avalonia.Metadata;
|
||||||
|
|
||||||
namespace Semi.Avalonia.TreeDataGrid.Demo.Converters;
|
namespace Semi.Avalonia.Demo.Converters;
|
||||||
|
|
||||||
public class FileIconConverter : IMultiValueConverter
|
public class FileIconConverter : IMultiValueConverter
|
||||||
{
|
{
|
||||||
127
demo/Semi.Avalonia.Demo/Pages/TreeDataGridDemo.axaml
Normal file
127
demo/Semi.Avalonia.Demo/Pages/TreeDataGridDemo.axaml
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:vm="clr-namespace:Semi.Avalonia.Demo.ViewModels"
|
||||||
|
xmlns:converters="clr-namespace:Semi.Avalonia.Demo.Converters"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Semi.Avalonia.Demo.Pages.TreeDataGridDemo"
|
||||||
|
x:CompileBindings="True"
|
||||||
|
x:DataType="vm:TreeDataGridDemoViewModel">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<converters:FileIconConverter x:Key="FileIconConverter">
|
||||||
|
<StaticResource x:Key="file" ResourceKey="SemiIconFile" />
|
||||||
|
<StaticResource x:Key="folderOpen" ResourceKey="SemiIconFolderOpen" />
|
||||||
|
<StaticResource x:Key="folderClosed" ResourceKey="SemiIconFolder" />
|
||||||
|
</converters:FileIconConverter>
|
||||||
|
</UserControl.Resources>
|
||||||
|
<TabControl>
|
||||||
|
<TabItem Header="Songs">
|
||||||
|
<TreeDataGrid
|
||||||
|
AutoDragDropRows="True"
|
||||||
|
DataContext="{Binding SongsContext}"
|
||||||
|
Source="{Binding Songs}">
|
||||||
|
<TreeDataGrid.Resources>
|
||||||
|
<DataTemplate x:Key="AlbumCell" DataType="vm:SongViewModel">
|
||||||
|
<TextBlock
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Background="Transparent"
|
||||||
|
Text="{Binding Album}" />
|
||||||
|
</DataTemplate>
|
||||||
|
<DataTemplate x:Key="AlbumEditCell" DataType="vm:SongViewModel">
|
||||||
|
<ComboBox
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Classes="Small"
|
||||||
|
ItemsSource="{x:Static vm:Song.Albums}"
|
||||||
|
SelectedItem="{Binding Album}" />
|
||||||
|
</DataTemplate>
|
||||||
|
<DataTemplate x:Key="CommentsCell" DataType="vm:SongViewModel">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="{Binding CountOfComment}" />
|
||||||
|
</DataTemplate>
|
||||||
|
<DataTemplate x:Key="CommentsEditCell" DataType="vm:SongViewModel">
|
||||||
|
<NumericUpDown
|
||||||
|
Width="100"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Classes="Small"
|
||||||
|
Value="{Binding CountOfComment}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</TreeDataGrid.Resources>
|
||||||
|
<TreeDataGrid.Styles>
|
||||||
|
<Style Selector="TreeDataGrid TreeDataGridRow:nth-last-child(2n)">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SemiColorFill0}" />
|
||||||
|
</Style>
|
||||||
|
</TreeDataGrid.Styles>
|
||||||
|
</TreeDataGrid>
|
||||||
|
</TabItem>
|
||||||
|
<TabItem Header="Files">
|
||||||
|
<Grid DataContext="{Binding FilesContext}" RowDefinitions="Auto, *">
|
||||||
|
<DockPanel Margin="0,4" DockPanel.Dock="Top">
|
||||||
|
<ComboBox
|
||||||
|
DockPanel.Dock="Left"
|
||||||
|
ItemsSource="{Binding Drives}"
|
||||||
|
SelectedItem="{Binding SelectedDrive}" />
|
||||||
|
<TextBox
|
||||||
|
Margin="4,0,0,0"
|
||||||
|
VerticalContentAlignment="Center"
|
||||||
|
KeyDown="SelectedPath_KeyDown"
|
||||||
|
Text="{Binding SelectedPath, Mode=OneWay}" />
|
||||||
|
</DockPanel>
|
||||||
|
<TreeDataGrid
|
||||||
|
Name="fileViewer"
|
||||||
|
Grid.Row="1"
|
||||||
|
Source="{Binding Source}">
|
||||||
|
<TreeDataGrid.Resources>
|
||||||
|
|
||||||
|
<!-- Template for Name column cells -->
|
||||||
|
<DataTemplate x:Key="FileNameCell" DataType="vm:FileNodeViewModel">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<PathIcon
|
||||||
|
Theme="{StaticResource InnerPathIcon}"
|
||||||
|
Margin="8,0">
|
||||||
|
<PathIcon.Data>
|
||||||
|
<MultiBinding Converter="{StaticResource FileIconConverter}">
|
||||||
|
<Binding Path="IsDirectory" />
|
||||||
|
<Binding Path="IsExpanded" />
|
||||||
|
</MultiBinding>
|
||||||
|
</PathIcon.Data>
|
||||||
|
</PathIcon>
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="{Binding Name}" />
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
|
||||||
|
<!-- Edit template for Name column cells -->
|
||||||
|
<DataTemplate x:Key="FileNameEditCell" DataType="vm:FileNodeViewModel">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Image Margin="0,0,4,0" VerticalAlignment="Center">
|
||||||
|
<Image.Source>
|
||||||
|
<MultiBinding Converter="{StaticResource FileIconConverter}">
|
||||||
|
<Binding Path="IsDirectory" />
|
||||||
|
<Binding Path="IsExpanded" />
|
||||||
|
</MultiBinding>
|
||||||
|
</Image.Source>
|
||||||
|
</Image>
|
||||||
|
<TextBox
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Classes="Small"
|
||||||
|
Text="{Binding Name}">
|
||||||
|
<TextBox.Styles>
|
||||||
|
<Style Selector="DataValidationErrors">
|
||||||
|
<Setter Property="Theme" Value="{DynamicResource TooltipDataValidationErrors}" />
|
||||||
|
</Style>
|
||||||
|
</TextBox.Styles>
|
||||||
|
</TextBox>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</TreeDataGrid.Resources>
|
||||||
|
<TreeDataGrid.Styles>
|
||||||
|
<Style Selector="TreeDataGrid TreeDataGridRow:nth-child(2n)">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SemiColorFill0}" />
|
||||||
|
</Style>
|
||||||
|
</TreeDataGrid.Styles>
|
||||||
|
</TreeDataGrid>
|
||||||
|
</Grid>
|
||||||
|
</TabItem>
|
||||||
|
</TabControl>
|
||||||
|
</UserControl>
|
||||||
23
demo/Semi.Avalonia.Demo/Pages/TreeDataGridDemo.axaml.cs
Normal file
23
demo/Semi.Avalonia.Demo/Pages/TreeDataGridDemo.axaml.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Semi.Avalonia.Demo.ViewModels;
|
||||||
|
|
||||||
|
namespace Semi.Avalonia.Demo.Pages;
|
||||||
|
|
||||||
|
public partial class TreeDataGridDemo : UserControl
|
||||||
|
{
|
||||||
|
public TreeDataGridDemo()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.DataContext = new TreeDataGridDemoViewModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SelectedPath_KeyDown(object? sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Key == Key.Enter)
|
||||||
|
{
|
||||||
|
var vm = DataContext as TreeDataGridDemoViewModel;
|
||||||
|
vm.FilesContext.SelectedPath = (sender as TextBox)!.Text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -25,5 +25,6 @@
|
|||||||
<ProjectReference Include="..\..\src\Semi.Avalonia\Semi.Avalonia.csproj"/>
|
<ProjectReference Include="..\..\src\Semi.Avalonia\Semi.Avalonia.csproj"/>
|
||||||
<ProjectReference Include="..\..\src\Semi.Avalonia.ColorPicker\Semi.Avalonia.ColorPicker.csproj"/>
|
<ProjectReference Include="..\..\src\Semi.Avalonia.ColorPicker\Semi.Avalonia.ColorPicker.csproj"/>
|
||||||
<ProjectReference Include="..\..\src\Semi.Avalonia.DataGrid\Semi.Avalonia.DataGrid.csproj"/>
|
<ProjectReference Include="..\..\src\Semi.Avalonia.DataGrid\Semi.Avalonia.DataGrid.csproj"/>
|
||||||
|
<ProjectReference Include="..\..\src\Semi.Avalonia.TreeDataGrid\Semi.Avalonia.TreeDataGrid.csproj"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -59,6 +59,25 @@ public class Song
|
|||||||
Url = $"https://music.163.com/song?id={netEaseId}";
|
Url = $"https://music.163.com/song?id={netEaseId}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<string> Albums =>
|
||||||
|
[
|
||||||
|
"A.S.I.A",
|
||||||
|
"饕餮人间",
|
||||||
|
"七步咙咚呛",
|
||||||
|
"大惊小怪",
|
||||||
|
"The ONE",
|
||||||
|
"以梦为马 (壮志骄阳版)",
|
||||||
|
"emo了",
|
||||||
|
"一眼万年",
|
||||||
|
"冲刺吧",
|
||||||
|
"爱的赏味期限",
|
||||||
|
"COSMIC ANTHEM / 手紙",
|
||||||
|
"世界晚安",
|
||||||
|
"明年也要好好长大",
|
||||||
|
"320万年前",
|
||||||
|
"W.O.R.L.D."
|
||||||
|
];
|
||||||
|
|
||||||
public static List<Song> Songs =>
|
public static List<Song> Songs =>
|
||||||
[
|
[
|
||||||
new("好肚有肚(feat.李玲玉)", "熊猫堂ProducePandas", 2, 50, "A.S.I.A", 730, 1487039339),
|
new("好肚有肚(feat.李玲玉)", "熊猫堂ProducePandas", 2, 50, "A.S.I.A", 730, 1487039339),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@@ -11,43 +12,35 @@ using Avalonia.Controls.Selection;
|
|||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
namespace Semi.Avalonia.TreeDataGrid.Demo.ViewModels;
|
namespace Semi.Avalonia.Demo.ViewModels;
|
||||||
|
|
||||||
public class FilesPageViewModel: ObservableObject
|
public partial class FilesPageViewModel : ObservableObject
|
||||||
{
|
{
|
||||||
public IList<string> Drives { get; }
|
public IList<string> Drives { get; }
|
||||||
private string _selectedDrive;
|
public HierarchicalTreeDataGridSource<FileNodeViewModel> Source { get; }
|
||||||
private string? _selectedPath;
|
[ObservableProperty] private string _selectedDrive;
|
||||||
private FileNodeViewModel? _root;
|
[ObservableProperty] private string? _selectedPath;
|
||||||
public string SelectedDrive
|
[ObservableProperty] private FileNodeViewModel? _root;
|
||||||
|
|
||||||
|
partial void OnSelectedDriveChanged(string value)
|
||||||
{
|
{
|
||||||
get => _selectedDrive;
|
Root = new FileNodeViewModel(value, true, true);
|
||||||
set
|
if (Source is not null)
|
||||||
{
|
{
|
||||||
SetProperty(ref _selectedDrive, value);
|
Source.Items = [Root];
|
||||||
_root = new FileNodeViewModel(_selectedDrive, isDirectory: true, isRoot: true);
|
|
||||||
Source.Items = new[] { _root };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string? SelectedPath
|
|
||||||
{
|
|
||||||
get => _selectedPath;
|
|
||||||
set => SetSelectedPath(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HierarchicalTreeDataGridSource<FileNodeViewModel> Source { get; }
|
|
||||||
|
|
||||||
public FilesPageViewModel()
|
public FilesPageViewModel()
|
||||||
{
|
{
|
||||||
Drives= DriveInfo.GetDrives().Select(x => x.Name).ToList();
|
Drives = DriveInfo.GetDrives().Select(x => x.Name).ToList();
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
{
|
{
|
||||||
_selectedDrive = "C:\\";
|
SelectedDrive = @"C:\";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_selectedDrive = Drives.FirstOrDefault() ?? "/";
|
SelectedDrive = Drives.FirstOrDefault() ?? "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
Source = new HierarchicalTreeDataGridSource<FileNodeViewModel>(Array.Empty<FileNodeViewModel>())
|
Source = new HierarchicalTreeDataGridSource<FileNodeViewModel>(Array.Empty<FileNodeViewModel>())
|
||||||
@@ -58,7 +51,7 @@ public class FilesPageViewModel: ObservableObject
|
|||||||
null,
|
null,
|
||||||
x => x.IsChecked,
|
x => x.IsChecked,
|
||||||
(o, v) => o.IsChecked = v,
|
(o, v) => o.IsChecked = v,
|
||||||
options: new()
|
options: new CheckBoxColumnOptions<FileNodeViewModel>
|
||||||
{
|
{
|
||||||
CanUserResizeColumn = false,
|
CanUserResizeColumn = false,
|
||||||
}),
|
}),
|
||||||
@@ -68,20 +61,20 @@ public class FilesPageViewModel: ObservableObject
|
|||||||
"FileNameCell",
|
"FileNameCell",
|
||||||
"FileNameEditCell",
|
"FileNameEditCell",
|
||||||
new GridLength(1, GridUnitType.Star),
|
new GridLength(1, GridUnitType.Star),
|
||||||
new()
|
new TemplateColumnOptions<FileNodeViewModel>
|
||||||
{
|
{
|
||||||
CompareAscending = FileNodeViewModel.SortAscending(x => x.Name),
|
CompareAscending = FileNodeViewModel.SortAscending(vm => vm.Name),
|
||||||
CompareDescending = FileNodeViewModel.SortDescending(x => x.Name),
|
CompareDescending = FileNodeViewModel.SortDescending(vm => vm.Name),
|
||||||
IsTextSearchEnabled = true,
|
IsTextSearchEnabled = true,
|
||||||
TextSearchValueSelector = x => x.Name
|
TextSearchValueSelector = vm => vm.Name
|
||||||
}),
|
}),
|
||||||
x => x.Children,
|
vm => vm.Children,
|
||||||
x => x.HasChildren,
|
vm => vm.HasChildren,
|
||||||
x => x.IsExpanded),
|
vm => vm.IsExpanded),
|
||||||
new TextColumn<FileNodeViewModel, long?>(
|
new TextColumn<FileNodeViewModel, long?>(
|
||||||
"Size",
|
"Size",
|
||||||
x => x.Size,
|
vm => vm.Size,
|
||||||
options: new()
|
options: new TextColumnOptions<FileNodeViewModel>
|
||||||
{
|
{
|
||||||
CompareAscending = FileNodeViewModel.SortAscending(x => x.Size),
|
CompareAscending = FileNodeViewModel.SortAscending(x => x.Size),
|
||||||
CompareDescending = FileNodeViewModel.SortDescending(x => x.Size),
|
CompareDescending = FileNodeViewModel.SortDescending(x => x.Size),
|
||||||
@@ -89,7 +82,7 @@ public class FilesPageViewModel: ObservableObject
|
|||||||
new TextColumn<FileNodeViewModel, DateTimeOffset?>(
|
new TextColumn<FileNodeViewModel, DateTimeOffset?>(
|
||||||
"Modified",
|
"Modified",
|
||||||
x => x.Modified,
|
x => x.Modified,
|
||||||
options: new()
|
options: new TextColumnOptions<FileNodeViewModel>
|
||||||
{
|
{
|
||||||
CompareAscending = FileNodeViewModel.SortAscending(x => x.Modified),
|
CompareAscending = FileNodeViewModel.SortAscending(x => x.Modified),
|
||||||
CompareDescending = FileNodeViewModel.SortDescending(x => x.Modified),
|
CompareDescending = FileNodeViewModel.SortDescending(x => x.Modified),
|
||||||
@@ -106,9 +99,9 @@ public class FilesPageViewModel: ObservableObject
|
|||||||
this.SetProperty(ref _selectedPath, selectedPath, nameof(SelectedPath));
|
this.SetProperty(ref _selectedPath, selectedPath, nameof(SelectedPath));
|
||||||
|
|
||||||
foreach (var i in e.DeselectedItems)
|
foreach (var i in e.DeselectedItems)
|
||||||
System.Diagnostics.Trace.WriteLine($"Deselected '{i?.Path}'");
|
Trace.WriteLine($"Deselected '{i?.Path}'");
|
||||||
foreach (var i in e.SelectedItems)
|
foreach (var i in e.SelectedItems)
|
||||||
System.Diagnostics.Trace.WriteLine($"Selected '{i?.Path}'");
|
Trace.WriteLine($"Selected '{i?.Path}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetSelectedPath(string? value)
|
private void SetSelectedPath(string? value)
|
||||||
@@ -168,23 +161,23 @@ public class FilesPageViewModel: ObservableObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FileNodeViewModel: ObservableObject, IEditableObject
|
public partial class FileNodeViewModel : ObservableObject, IEditableObject
|
||||||
{
|
{
|
||||||
private string _path;
|
[ObservableProperty] private string _path;
|
||||||
private string _name;
|
[ObservableProperty] private string _name;
|
||||||
private string? _undoName;
|
private string? _undoName;
|
||||||
private long? _size;
|
[ObservableProperty] private long? _size;
|
||||||
private DateTimeOffset? _modified;
|
[ObservableProperty] private DateTimeOffset? _modified;
|
||||||
private FileSystemWatcher? _watcher;
|
private FileSystemWatcher? _watcher;
|
||||||
private ObservableCollection<FileNodeViewModel>? _children;
|
private ObservableCollection<FileNodeViewModel>? _children;
|
||||||
private bool _hasChildren = true;
|
[ObservableProperty] private bool _hasChildren = true;
|
||||||
private bool _isExpanded;
|
[ObservableProperty] private bool _isExpanded;
|
||||||
|
|
||||||
public FileNodeViewModel( string path, bool isDirectory, bool isRoot = false)
|
public FileNodeViewModel(string path, bool isDirectory, bool isRoot = false)
|
||||||
{
|
{
|
||||||
_path = path;
|
Path = path;
|
||||||
_name = isRoot ? path : System.IO.Path.GetFileName(Path);
|
Name = isRoot ? path : System.IO.Path.GetFileName(Path);
|
||||||
_isExpanded = isRoot;
|
IsExpanded = isRoot;
|
||||||
IsDirectory = isDirectory;
|
IsDirectory = isDirectory;
|
||||||
HasChildren = isDirectory;
|
HasChildren = isDirectory;
|
||||||
|
|
||||||
@@ -196,42 +189,6 @@ public class FileNodeViewModel: ObservableObject, IEditableObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Path
|
|
||||||
{
|
|
||||||
get => _path;
|
|
||||||
private set => SetProperty(ref _path, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get => _name;
|
|
||||||
private set => SetProperty(ref _name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long? Size
|
|
||||||
{
|
|
||||||
get => _size;
|
|
||||||
private set => SetProperty(ref _size, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateTimeOffset? Modified
|
|
||||||
{
|
|
||||||
get => _modified;
|
|
||||||
private set => SetProperty(ref _modified, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasChildren
|
|
||||||
{
|
|
||||||
get => _hasChildren;
|
|
||||||
private set => SetProperty(ref _hasChildren, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsExpanded
|
|
||||||
{
|
|
||||||
get => _isExpanded;
|
|
||||||
set => SetProperty(ref _isExpanded, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsChecked { get; set; }
|
public bool IsChecked { get; set; }
|
||||||
public bool IsDirectory { get; }
|
public bool IsDirectory { get; }
|
||||||
public IReadOnlyList<FileNodeViewModel> Children => _children ??= LoadChildren();
|
public IReadOnlyList<FileNodeViewModel> Children => _children ??= LoadChildren();
|
||||||
@@ -332,6 +289,7 @@ public class FileNodeViewModel: ObservableObject, IEditableObject
|
|||||||
child.Size = info.Length;
|
child.Size = info.Length;
|
||||||
child.Modified = info.LastWriteTimeUtc;
|
child.Modified = info.LastWriteTimeUtc;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -359,7 +317,7 @@ public class FileNodeViewModel: ObservableObject, IEditableObject
|
|||||||
if (_children[i].Path == e.FullPath)
|
if (_children[i].Path == e.FullPath)
|
||||||
{
|
{
|
||||||
_children.RemoveAt(i);
|
_children.RemoveAt(i);
|
||||||
System.Diagnostics.Debug.WriteLine($"Removed {e.FullPath}");
|
Debug.WriteLine($"Removed {e.FullPath}");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -394,6 +352,7 @@ internal static class ListExtensions
|
|||||||
return i;
|
return i;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Models.TreeDataGrid;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
|
namespace Semi.Avalonia.Demo.ViewModels;
|
||||||
|
|
||||||
|
public class SongsPageViewModel : ObservableObject
|
||||||
|
{
|
||||||
|
public FlatTreeDataGridSource<SongViewModel> Songs { get; }
|
||||||
|
|
||||||
|
public SongsPageViewModel()
|
||||||
|
{
|
||||||
|
var songs = new ObservableCollection<SongViewModel>(Song.Songs.Select(a => new SongViewModel()
|
||||||
|
{
|
||||||
|
Title = a.Title,
|
||||||
|
Artist = a.Artist,
|
||||||
|
Album = a.Album,
|
||||||
|
CountOfComment = a.CountOfComment,
|
||||||
|
IsSelected = false
|
||||||
|
}));
|
||||||
|
|
||||||
|
Songs = new FlatTreeDataGridSource<SongViewModel>(songs)
|
||||||
|
{
|
||||||
|
Columns =
|
||||||
|
{
|
||||||
|
new CheckBoxColumn<SongViewModel>(
|
||||||
|
"IsSelected",
|
||||||
|
a => a.IsSelected,
|
||||||
|
(model, b) => { model.IsSelected = b; },
|
||||||
|
new GridLength(108, GridUnitType.Pixel)),
|
||||||
|
new TextColumn<SongViewModel, string>(
|
||||||
|
"Title",
|
||||||
|
a => a.Title,
|
||||||
|
(o, a) => o.Title = a,
|
||||||
|
new GridLength(6, GridUnitType.Star)),
|
||||||
|
new TextColumn<SongViewModel, string>("Artist",
|
||||||
|
a => a.Artist,
|
||||||
|
(o, a) => o.Artist = a,
|
||||||
|
new GridLength(6, GridUnitType.Star)),
|
||||||
|
new TemplateColumn<SongViewModel>("Album",
|
||||||
|
"AlbumCell",
|
||||||
|
"AlbumEditCell",
|
||||||
|
new GridLength(6, GridUnitType.Star)),
|
||||||
|
new TemplateColumn<SongViewModel>(
|
||||||
|
"Comments",
|
||||||
|
"CommentsCell",
|
||||||
|
"CommentsEditCell",
|
||||||
|
new GridLength(6, GridUnitType.Star)),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
namespace Semi.Avalonia.TreeDataGrid.Demo.ViewModels;
|
namespace Semi.Avalonia.Demo.ViewModels;
|
||||||
|
|
||||||
public class MainViewModel: ObservableObject
|
public class TreeDataGridDemoViewModel: ObservableObject
|
||||||
{
|
{
|
||||||
public SongsPageViewModel SongsContext { get; } = new();
|
public SongsPageViewModel SongsContext { get; } = new();
|
||||||
public FilesPageViewModel FilesContext { get; } = new();
|
public FilesPageViewModel FilesContext { get; } = new();
|
||||||
@@ -135,6 +135,9 @@
|
|||||||
<TabItem Header="DataGrid">
|
<TabItem Header="DataGrid">
|
||||||
<pages:DataGridDemo />
|
<pages:DataGridDemo />
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
<TabItem Header="TreeDataGrid">
|
||||||
|
<pages:TreeDataGridDemo />
|
||||||
|
</TabItem>
|
||||||
<TabItem
|
<TabItem
|
||||||
Theme="{DynamicResource CategoryTabItem}"
|
Theme="{DynamicResource CategoryTabItem}"
|
||||||
Header="Basic" />
|
Header="Basic" />
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
<Application
|
|
||||||
x:Class="Semi.Avalonia.TreeDataGrid.Demo.App"
|
|
||||||
xmlns="https://github.com/avaloniaui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:semi="https://irihi.tech/semi">
|
|
||||||
|
|
||||||
<Application.Styles>
|
|
||||||
<semi:SemiTheme Locale="zh-CN" />
|
|
||||||
<StyleInclude Source="avares://Semi.Avalonia.TreeDataGrid/Index.axaml" />
|
|
||||||
</Application.Styles>
|
|
||||||
</Application>
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
|
||||||
using Avalonia.Markup.Xaml;
|
|
||||||
|
|
||||||
namespace Semi.Avalonia.TreeDataGrid.Demo;
|
|
||||||
|
|
||||||
public partial class App : Application
|
|
||||||
{
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
AvaloniaXamlLoader.Load(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnFrameworkInitializationCompleted()
|
|
||||||
{
|
|
||||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
|
||||||
{
|
|
||||||
desktop.MainWindow = new MainWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnFrameworkInitializationCompleted();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
<Window
|
|
||||||
x:Class="Semi.Avalonia.TreeDataGrid.Demo.MainWindow"
|
|
||||||
xmlns="https://github.com/avaloniaui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:converters="clr-namespace:Semi.Avalonia.TreeDataGrid.Demo.Converters"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:vm="clr-namespace:Semi.Avalonia.TreeDataGrid.Demo.ViewModels;assembly=Semi.Avalonia.TreeDataGrid.Demo"
|
|
||||||
Title="Semi.Avalonia.TreeDataGrid.Demo"
|
|
||||||
d:DesignHeight="450"
|
|
||||||
d:DesignWidth="800"
|
|
||||||
x:DataType="vm:MainViewModel"
|
|
||||||
mc:Ignorable="d">
|
|
||||||
<Window.Resources>
|
|
||||||
<converters:FileIconConverter x:Key="FileIconConverter">
|
|
||||||
<StaticResource x:Key="file" ResourceKey="SemiIconFile" />
|
|
||||||
<StaticResource x:Key="folderOpen" ResourceKey="SemiIconFolderOpen" />
|
|
||||||
<StaticResource x:Key="folderClosed" ResourceKey="SemiIconFolder" />
|
|
||||||
</converters:FileIconConverter>
|
|
||||||
</Window.Resources>
|
|
||||||
<Grid RowDefinitions="Auto, *">
|
|
||||||
<Button
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
Click="Button_OnClick"
|
|
||||||
Content="Theme" />
|
|
||||||
<TabControl Grid.Row="1">
|
|
||||||
<TabItem Header="Songs">
|
|
||||||
<TreeDataGrid
|
|
||||||
AutoDragDropRows="True"
|
|
||||||
DataContext="{Binding SongsContext}"
|
|
||||||
Source="{Binding Songs}">
|
|
||||||
<TreeDataGrid.Resources>
|
|
||||||
<DataTemplate x:Key="AlbumCell" DataType="vm:SongViewModel">
|
|
||||||
<TextBlock
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Background="Transparent"
|
|
||||||
Text="{Binding Album}" />
|
|
||||||
</DataTemplate>
|
|
||||||
<DataTemplate x:Key="AlbumEditCell" DataType="vm:SongViewModel">
|
|
||||||
<ComboBox
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Classes="Small"
|
|
||||||
ItemsSource="{x:Static vm:Song.Albums}"
|
|
||||||
SelectedItem="{Binding Album}" />
|
|
||||||
</DataTemplate>
|
|
||||||
<DataTemplate x:Key="CommentsCell" DataType="vm:SongViewModel">
|
|
||||||
<TextBlock VerticalAlignment="Center" Text="{Binding CountOfComment}" />
|
|
||||||
</DataTemplate>
|
|
||||||
<DataTemplate x:Key="CommentsEditCell" DataType="vm:SongViewModel">
|
|
||||||
<NumericUpDown
|
|
||||||
Width="100"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Classes="Small"
|
|
||||||
Value="{Binding CountOfComment}" />
|
|
||||||
</DataTemplate>
|
|
||||||
</TreeDataGrid.Resources>
|
|
||||||
<TreeDataGrid.Styles>
|
|
||||||
<Style Selector="TreeDataGrid TreeDataGridRow:nth-last-child(2n)">
|
|
||||||
<Setter Property="Background" Value="{DynamicResource SemiColorFill0}" />
|
|
||||||
</Style>
|
|
||||||
</TreeDataGrid.Styles>
|
|
||||||
</TreeDataGrid>
|
|
||||||
</TabItem>
|
|
||||||
<TabItem Header="Files">
|
|
||||||
<Grid DataContext="{Binding FilesContext}" RowDefinitions="Auto, *">
|
|
||||||
<DockPanel Margin="0,4" DockPanel.Dock="Top">
|
|
||||||
<ComboBox
|
|
||||||
DockPanel.Dock="Left"
|
|
||||||
ItemsSource="{Binding Drives}"
|
|
||||||
SelectedItem="{Binding SelectedDrive}" />
|
|
||||||
<TextBox
|
|
||||||
Margin="4,0,0,0"
|
|
||||||
VerticalContentAlignment="Center"
|
|
||||||
KeyDown="SelectedPath_KeyDown"
|
|
||||||
Text="{Binding SelectedPath, Mode=OneWay}" />
|
|
||||||
</DockPanel>
|
|
||||||
<TreeDataGrid
|
|
||||||
Name="fileViewer"
|
|
||||||
Grid.Row="1"
|
|
||||||
Source="{Binding Source}">
|
|
||||||
<TreeDataGrid.Resources>
|
|
||||||
|
|
||||||
<!-- Template for Name column cells -->
|
|
||||||
<DataTemplate x:Key="FileNameCell" DataType="vm:FileNodeViewModel">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<PathIcon
|
|
||||||
Theme="{StaticResource InnerPathIcon}"
|
|
||||||
Margin="8,0">
|
|
||||||
<PathIcon.Data>
|
|
||||||
<MultiBinding Converter="{StaticResource FileIconConverter}">
|
|
||||||
<Binding Path="IsDirectory" />
|
|
||||||
<Binding Path="IsExpanded" />
|
|
||||||
</MultiBinding>
|
|
||||||
</PathIcon.Data>
|
|
||||||
</PathIcon>
|
|
||||||
<TextBlock VerticalAlignment="Center" Text="{Binding Name}" />
|
|
||||||
</StackPanel>
|
|
||||||
</DataTemplate>
|
|
||||||
|
|
||||||
<!-- Edit template for Name column cells -->
|
|
||||||
<DataTemplate x:Key="FileNameEditCell" DataType="vm:FileNodeViewModel">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<Image Margin="0,0,4,0" VerticalAlignment="Center">
|
|
||||||
<Image.Source>
|
|
||||||
<MultiBinding Converter="{StaticResource FileIconConverter}">
|
|
||||||
<Binding Path="IsDirectory" />
|
|
||||||
<Binding Path="IsExpanded" />
|
|
||||||
</MultiBinding>
|
|
||||||
</Image.Source>
|
|
||||||
</Image>
|
|
||||||
<TextBox
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Classes="Small"
|
|
||||||
Text="{Binding Name}">
|
|
||||||
<TextBox.Styles>
|
|
||||||
<Style Selector="DataValidationErrors">
|
|
||||||
<Setter Property="Theme" Value="{DynamicResource TooltipDataValidationErrors}" />
|
|
||||||
</Style>
|
|
||||||
</TextBox.Styles>
|
|
||||||
</TextBox>
|
|
||||||
</StackPanel>
|
|
||||||
</DataTemplate>
|
|
||||||
</TreeDataGrid.Resources>
|
|
||||||
<TreeDataGrid.Styles>
|
|
||||||
<Style Selector="TreeDataGrid TreeDataGridRow:nth-child(2n)">
|
|
||||||
<Setter Property="Background" Value="{DynamicResource SemiColorFill0}" />
|
|
||||||
</Style>
|
|
||||||
</TreeDataGrid.Styles>
|
|
||||||
</TreeDataGrid>
|
|
||||||
</Grid>
|
|
||||||
</TabItem>
|
|
||||||
</TabControl>
|
|
||||||
</Grid>
|
|
||||||
</Window>
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Input;
|
|
||||||
using Avalonia.Interactivity;
|
|
||||||
using Avalonia.Styling;
|
|
||||||
using Semi.Avalonia.TreeDataGrid.Demo.ViewModels;
|
|
||||||
|
|
||||||
namespace Semi.Avalonia.TreeDataGrid.Demo;
|
|
||||||
|
|
||||||
public partial class MainWindow : Window
|
|
||||||
{
|
|
||||||
public MainWindow()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
this.DataContext = new MainViewModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Button_OnClick(object? sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
var app = Application.Current;
|
|
||||||
if (app is not null)
|
|
||||||
{
|
|
||||||
var theme = app.ActualThemeVariant;
|
|
||||||
app.RequestedThemeVariant = theme == ThemeVariant.Dark ? ThemeVariant.Light : ThemeVariant.Dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SelectedPath_KeyDown(object? sender, KeyEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.Key == Key.Enter)
|
|
||||||
{
|
|
||||||
var vm = (MainViewModel)DataContext!;
|
|
||||||
vm.FilesContext.SelectedPath = ((TextBox)sender!).Text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Avalonia;
|
|
||||||
using Avalonia.Media;
|
|
||||||
|
|
||||||
namespace Semi.Avalonia.TreeDataGrid.Demo;
|
|
||||||
|
|
||||||
sealed class Program
|
|
||||||
{
|
|
||||||
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
|
||||||
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
|
||||||
// yet and stuff might break.
|
|
||||||
[STAThread]
|
|
||||||
public static void Main(string[] args) => BuildAvaloniaApp()
|
|
||||||
.With(new FontManagerOptions
|
|
||||||
{
|
|
||||||
FontFallbacks =
|
|
||||||
[
|
|
||||||
new FontFallback
|
|
||||||
{
|
|
||||||
FontFamily = new FontFamily("Microsoft YaHei")
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
.StartWithClassicDesktopLifetime(args);
|
|
||||||
|
|
||||||
// Avalonia configuration, don't remove; also used by visual designer.
|
|
||||||
public static AppBuilder BuildAvaloniaApp()
|
|
||||||
=> AppBuilder.Configure<App>()
|
|
||||||
.UsePlatformDetect()
|
|
||||||
.LogToTrace();
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>WinExe</OutputType>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
|
||||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
|
||||||
<!-- Uncomment below to enable Native AOT compilation-->
|
|
||||||
<!--<PublishAot>true</PublishAot>-->
|
|
||||||
<!--<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>-->
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<Import Project="../Directory.Build.props"/>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Avalonia" Version="$(AvaloniaVersion)"/>
|
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="$(AvaloniaVersion)"/>
|
|
||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
|
||||||
<PackageReference Include="Avalonia.Diagnostics" Version="$(AvaloniaVersion)">
|
|
||||||
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
|
||||||
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="$(CommunityToolkitVersion)"/>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\src\Semi.Avalonia.TreeDataGrid\Semi.Avalonia.TreeDataGrid.csproj"/>
|
|
||||||
<ProjectReference Include="..\..\src\Semi.Avalonia\Semi.Avalonia.csproj"/>
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Linq;
|
|
||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Controls.Models.TreeDataGrid;
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
|
||||||
|
|
||||||
namespace Semi.Avalonia.TreeDataGrid.Demo.ViewModels;
|
|
||||||
|
|
||||||
public class SongsPageViewModel: ObservableObject
|
|
||||||
{
|
|
||||||
private readonly ObservableCollection<SongViewModel> _songs;
|
|
||||||
|
|
||||||
public FlatTreeDataGridSource<SongViewModel> Songs { get; }
|
|
||||||
|
|
||||||
public SongsPageViewModel()
|
|
||||||
{
|
|
||||||
_songs = new ObservableCollection<SongViewModel>(Song.Songs.Select(a => new SongViewModel()
|
|
||||||
{
|
|
||||||
Title = a.Title, Artist = a.Artist, Album = a.Album, CountOfComment = a.CountOfComment,
|
|
||||||
IsSelected = false
|
|
||||||
}));
|
|
||||||
|
|
||||||
Songs = new FlatTreeDataGridSource<SongViewModel>(_songs)
|
|
||||||
{
|
|
||||||
Columns =
|
|
||||||
{
|
|
||||||
new CheckBoxColumn<SongViewModel>("IsSelected", a => a.IsSelected,
|
|
||||||
(model, b) => { model.IsSelected = b; }, new GridLength(108, GridUnitType.Pixel)),
|
|
||||||
new TextColumn<SongViewModel, string>("Title", a => a.Title, (o, a) => o.Title = a,
|
|
||||||
new GridLength(6, GridUnitType.Star)),
|
|
||||||
new TextColumn<SongViewModel, string>("Artist", a => a.Artist, (o, a) => o.Artist = a,
|
|
||||||
new GridLength(6, GridUnitType.Star)),
|
|
||||||
new TemplateColumn<SongViewModel>("Album", "AlbumCell", "AlbumEditCell",
|
|
||||||
new GridLength(6, GridUnitType.Star)),
|
|
||||||
new TemplateColumn<SongViewModel>("Comments", "CommentsCell", "CommentsEditCell",
|
|
||||||
new GridLength(6, GridUnitType.Star)),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public class Song
|
|
||||||
{
|
|
||||||
public string? Title { get; set; }
|
|
||||||
public string? Artist { get; set; }
|
|
||||||
public TimeSpan? Duration { get; set; }
|
|
||||||
public string? Album { get; set; }
|
|
||||||
public int? CountOfComment { get; set; }
|
|
||||||
public string Url { get; set; }
|
|
||||||
|
|
||||||
public Song(string title, string artist, int m, int s, string album, int countOfComment, int netEaseId)
|
|
||||||
{
|
|
||||||
Title = title;
|
|
||||||
Artist = artist;
|
|
||||||
Duration = new TimeSpan(0, m, s);
|
|
||||||
Album = album;
|
|
||||||
CountOfComment = countOfComment;
|
|
||||||
Url = $"https://music.163.com/song?id={netEaseId}";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<string> Albums { get; set; } = new List<string>()
|
|
||||||
{
|
|
||||||
"A.S.I.A",
|
|
||||||
"饕餮人间",
|
|
||||||
"七步咙咚呛",
|
|
||||||
"大惊小怪",
|
|
||||||
"The ONE",
|
|
||||||
"以梦为马 (壮志骄阳版)",
|
|
||||||
"emo了",
|
|
||||||
"一眼万年",
|
|
||||||
"冲刺吧",
|
|
||||||
"爱的赏味期限",
|
|
||||||
"COSMIC ANTHEM / 手紙",
|
|
||||||
"世界晚安",
|
|
||||||
"明年也要好好长大",
|
|
||||||
"320万年前",
|
|
||||||
"W.O.R.L.D.",
|
|
||||||
};
|
|
||||||
|
|
||||||
public static List<Song> Songs { get; set; } = new List<Song>()
|
|
||||||
{
|
|
||||||
new("好肚有肚(feat.李玲玉)", "熊猫堂ProducePandas", 2, 50, "A.S.I.A", 730, 1487039339),
|
|
||||||
new("荒诞秀", "熊猫堂ProducePandas", 3, 15, "A.S.I.A", 639, 1487037601),
|
|
||||||
new("长大", "熊猫堂ProducePandas", 4, 6, "A.S.I.A", 1114, 1487037690),
|
|
||||||
new("招财猫(feat.纪粹希(G-Tracy))", "熊猫堂ProducePandas", 3, 37, "A.S.I.A", 361, 1487039632),
|
|
||||||
new("千转", "熊猫堂ProducePandas", 4, 0, "A.S.I.A", 1115, 1477312398),
|
|
||||||
new("辣辣辣", "熊猫堂ProducePandas", 3, 24, "A.S.I.A", 1873, 1465043716),
|
|
||||||
new("碎碎念", "熊猫堂ProducePandas", 3, 25, "A.S.I.A", 676, 1474142064),
|
|
||||||
new("盘他", "熊猫堂ProducePandas", 2, 16, "A.S.I.A", 365, 1481652786),
|
|
||||||
new("Na Na Na", "熊猫堂ProducePandas", 3, 26, "A.S.I.A", 312, 1469022662),
|
|
||||||
new("Indigo", "熊猫堂ProducePandas", 3, 15, "A.S.I.A", 137, 1487039517),
|
|
||||||
new("饕餮人间", "熊猫堂ProducePandas", 3, 20, "饕餮人间", 1295, 1499584605),
|
|
||||||
new("七步咙咚呛", "熊猫堂ProducePandas", 3, 10, "七步咙咚呛", 175, 1809095152),
|
|
||||||
new("大惊小怪", "熊猫堂ProducePandas", 3, 32, "大惊小怪", 10420, 1847477425),
|
|
||||||
new("工具人", "熊猫堂ProducePandas", 2, 46, "大惊小怪", 1135, 1847476499),
|
|
||||||
new("以梦为马", "熊猫堂ProducePandas", 4, 19, "大惊小怪", 18361, 1836034373),
|
|
||||||
new("以梦为马(Piano Version)", "熊猫堂ProducePandas", 3, 4, "大惊小怪", 570, 1847477423),
|
|
||||||
new("The ONE", "熊猫堂ProducePandas", 2, 58, "The ONE", 1508, 1864329424),
|
|
||||||
new("The ONE(日文版)", "熊猫堂ProducePandas", 2, 57, "The ONE", 385, 1864329429),
|
|
||||||
new("以梦为马 (壮志骄阳版)", "熊猫堂ProducePandas", 4, 19, "以梦为马 (壮志骄阳版)", 161, 1865138896),
|
|
||||||
new("New Horse", "熊猫堂ProducePandas", 2, 30, "emo了", 643, 1887021307),
|
|
||||||
new("不例外", "熊猫堂ProducePandas", 3, 31, "emo了", 1818, 1887022665),
|
|
||||||
new("满意", "熊猫堂ProducePandas", 4, 32, "emo了", 1081, 1882433472),
|
|
||||||
new("就算与全世界为敌也要跟你在一起", "熊猫堂ProducePandas", 3, 32, "emo了", 2119, 1881759960),
|
|
||||||
new("The ONE", "熊猫堂ProducePandas", 2, 58, "emo了", 67, 1887022648),
|
|
||||||
new("口香糖", "熊猫堂ProducePandas", 3, 10, "emo了", 2181, 1885502254),
|
|
||||||
new("Suuuuuuper Mario", "熊猫堂ProducePandas", 3, 32, "emo了", 1010, 1887021318),
|
|
||||||
new("饕餮人间", "熊猫堂ProducePandas", 3, 22, "emo了", 109, 1887021320),
|
|
||||||
new("以梦为马 (壮志骄阳版)", "熊猫堂ProducePandas", 4, 21, "emo了", 34, 1887022666),
|
|
||||||
new("The ONE(日文版)", "熊猫堂ProducePandas", 2, 57, "emo了", 27, 1887022646),
|
|
||||||
new("满意(DJheap九天版)", "熊猫堂ProducePandas", 4, 31, "emo了", 31, 1901605941),
|
|
||||||
new("一眼万年", "熊猫堂ProducePandas", 3, 54, "一眼万年", 20, 1922599361),
|
|
||||||
new("冲刺", "熊猫堂ProducePandas", 3, 49, "冲刺吧", 1006, 1932878194),
|
|
||||||
new("滴答滴", "熊猫堂ProducePandas", 2, 30, "爱的赏味期限", 86, 1957515790),
|
|
||||||
new("热带季风", "熊猫堂ProducePandas", 2, 45, "爱的赏味期限", 212, 1957514964),
|
|
||||||
new("渣", "熊猫堂ProducePandas", 3, 28, "爱的赏味期限", 22, 1957514965),
|
|
||||||
new("独特", "熊猫堂ProducePandas", 3, 33, "爱的赏味期限", 62, 1957514966),
|
|
||||||
new("雨后", "熊猫堂ProducePandas", 4, 15, "爱的赏味期限", 23, 1957514967),
|
|
||||||
new("然后然后", "熊猫堂ProducePandas", 3, 50, "爱的赏味期限", 108, 1957514968),
|
|
||||||
new("丢", "熊猫堂ProducePandas", 3, 26, "爱的赏味期限", 30, 1957515792),
|
|
||||||
new("热带疾风(FACEVOID桃心连哥 Remix)", "熊猫堂ProducePandas", 3, 23, "爱的赏味期限", 55, 1957515793),
|
|
||||||
new("COSMIC ANTHEM -Japanese Ver.-", "熊猫堂ProducePandas", 3, 11, "COSMIC ANTHEM / 手紙", 0, 1977171493),
|
|
||||||
new("手紙 (「長大-You Raise Me Up-」-Japanese Ver.-)", "熊猫堂ProducePandas", 4, 11, "COSMIC ANTHEM / 手紙", 0,
|
|
||||||
1977171494),
|
|
||||||
new("COSMIC ANTHEM -Chinese Ver.-", "熊猫堂ProducePandas", 3, 31, "COSMIC ANTHEM / 手紙", 0, 1977172202),
|
|
||||||
new("世界晚安", "熊猫堂ProducePandas", 2, 59, "世界晚安", 652, 1985063377),
|
|
||||||
new("世界晚安(泰文版)", "熊猫堂ProducePandas", 2, 59, "世界晚安", 134, 1987842504),
|
|
||||||
new("世界晚安(钢琴版)", "熊猫堂ProducePandas", 3, 2, "世界晚安", 76, 1990475933),
|
|
||||||
new("世界晚安(泰文钢琴版)", "熊猫堂ProducePandas", 3, 2, "世界晚安", 29, 1990475934),
|
|
||||||
new("世界晚安(DJ沈念版)", "熊猫堂ProducePandas", 3, 9, "世界晚安", 34, 2014263184),
|
|
||||||
new("世界晚安(钢琴配乐)", "熊猫堂ProducePandas", 2, 59, "世界晚安", 11, 2014263185),
|
|
||||||
new("明年也要好好长大", "熊猫堂ProducePandas", 3, 12, "明年也要好好长大", 0, 2010515162),
|
|
||||||
new("320万年前(DJ沈念版)", "熊猫堂ProducePandas", 3, 21, "320万年前", 8, 2055888636),
|
|
||||||
new("320万年前", "熊猫堂ProducePandas", 3, 7, "W.O.R.L.D.", 329, 2049770469),
|
|
||||||
new("隐德来希", "熊猫堂ProducePandas", 3, 3, "W.O.R.L.D.", 594, 2061317924),
|
|
||||||
new("孔明", "熊猫堂ProducePandas", 3, 59, "W.O.R.L.D.", 91, 2063175274),
|
|
||||||
new("锦鲤卟噜噜", "熊猫堂ProducePandas", 3, 5, "W.O.R.L.D.", 67, 2059208262),
|
|
||||||
new("指鹿为马", "熊猫堂ProducePandas", 3, 12, "W.O.R.L.D.", 74, 2063175272),
|
|
||||||
new("热带季风Remix", "熊猫堂ProducePandas", 3, 22, "W.O.R.L.D.", 23, 2063173319),
|
|
||||||
new("加州梦境", "熊猫堂ProducePandas", 2, 56, "W.O.R.L.D.", 1662, 2063173324),
|
|
||||||
new("渐进自由", "熊猫堂ProducePandas", 4, 19, "W.O.R.L.D.", 124, 2063173321),
|
|
||||||
new("世界所有的烂漫", "熊猫堂ProducePandas", 3, 30, "W.O.R.L.D.", 335, 2053388775),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SongViewModel: ObservableObject
|
|
||||||
{
|
|
||||||
private string? _title;
|
|
||||||
private string? _artist;
|
|
||||||
private string? _album;
|
|
||||||
private int? _countOfComment;
|
|
||||||
private bool? _isSelected;
|
|
||||||
public string? Title
|
|
||||||
{
|
|
||||||
get => _title;
|
|
||||||
set => SetProperty(ref _title, value);
|
|
||||||
}
|
|
||||||
public string? Artist
|
|
||||||
{
|
|
||||||
get => _artist;
|
|
||||||
set => SetProperty(ref _artist, value);
|
|
||||||
}
|
|
||||||
public string? Album
|
|
||||||
{
|
|
||||||
get => _album;
|
|
||||||
set => SetProperty(ref _album, value);
|
|
||||||
}
|
|
||||||
public int? CountOfComment
|
|
||||||
{
|
|
||||||
get => _countOfComment;
|
|
||||||
set => SetProperty(ref _countOfComment, value);
|
|
||||||
}
|
|
||||||
public bool? IsSelected
|
|
||||||
{
|
|
||||||
get => _isSelected;
|
|
||||||
set => SetProperty(ref _isSelected, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<!-- This manifest is used on Windows only.
|
|
||||||
Don't remove it as it might cause problems with window transparency and embeded controls.
|
|
||||||
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
|
|
||||||
<assemblyIdentity version="1.0.0.0" name="Semi.Avalonia.TreeDataGrid.Demo.Desktop"/>
|
|
||||||
|
|
||||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
|
||||||
<application>
|
|
||||||
<!-- A list of the Windows versions that this application has been tested on
|
|
||||||
and is designed to work with. Uncomment the appropriate elements
|
|
||||||
and Windows will automatically select the most compatible environment. -->
|
|
||||||
|
|
||||||
<!-- Windows 10 -->
|
|
||||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
|
||||||
</application>
|
|
||||||
</compatibility>
|
|
||||||
</assembly>
|
|
||||||
Reference in New Issue
Block a user