WPF Treeview - Определить родительские и дочерние узлы? - PullRequest
0 голосов
/ 01 ноября 2018

Я пытаюсь реализовать TreeView в WPF, чтобы показать детям, которые отображают активность начисления, корректировку и т. Д. На ежедневном балансе счета. Я собирался начать с того, что сначала отобразил данные ежедневного баланса счета в качестве родительского узла (что я успешно сделал), а затем попытался, например, показать текстовый сегмент в качестве дочернего для тестирования, а затем развернуть его, чтобы показать дочерние элементы. что я бы предпочел представлять в виде таблиц, чтобы показать, что было начислено в тот день, а затем отдельно, что было скорректировано на заряд в тот день, и т. д. Это то, где я застрял.

Вот мой код XAML:

<Window x:Class="Client_Invoice_Auditor.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        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:local="clr-namespace:Client_Invoice_Auditor"
        xmlns:self="clr-namespace:Client_Invoice_Auditor.CoreClientAR"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Grid>
        <Grid.ColumnDefinitions>

        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="20*"/>
            <RowDefinition Height="80*"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0" Grid.Column="0">
            <StackPanel Orientation="Vertical">
                <DockPanel VerticalAlignment="Top" Height="20" Panel.ZIndex="1">
                    <Menu Name="fileMenu" Width="Auto" DockPanel.Dock="Top">
                        <MenuItem Header="File">
                            <MenuItem Header="Open Account File" Click="menuOpenFile_Click"/>
                            <MenuItem Header="Exit" Click="menuExit_Click"/>
                        </MenuItem>
                        <MenuItem Header="Options">
                            <!--<MenuItem Header="Update" Click="update_Click"/>-->
                            <MenuItem Header="About" Click="about_Click"/>
                        </MenuItem>
                    </Menu>
                </DockPanel>
                <WrapPanel Orientation="Horizontal" HorizontalAlignment="Center" Height="Auto">
                    <StackPanel Width="Auto" Orientation="Horizontal" HorizontalAlignment="Center">
                        <Border BorderBrush="MediumAquamarine" BorderThickness="2">
                            <Label Name="AccountNumber"/>
                        </Border>
                        <Border BorderBrush="MediumAquamarine" BorderThickness="2">
                            <Label Name="AcctDesc"/>
                        </Border>
                        <Border BorderBrush="MediumAquamarine" BorderThickness="2">
                            <Label Name="Organization"/>
                        </Border>
                    </StackPanel>
                </WrapPanel>
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
                    <Label Margin="20,10,0,0" Content="Activity Date Time" />
                    <Label Margin="60,10,0,0" Content="Beginning Balance" />
                    <Label Margin="10,10,0,0" Content="Charge Amount" />
                    <Label Margin="30,10,0,0" Content="Adjustments" />
                    <Label Margin="40,10,0,0" Content="Payments" />
                    <Label Margin="60,10,0,0" Content="End Balance" />
                </StackPanel>
            </StackPanel>

        </Grid>
        <Grid Grid.Row="1" Grid.Column="0">
            <TreeView Name="DABView">
                <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type self:dailyAccountBalance}">
                    <StackPanel Orientation="Horizontal">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
                                <TextBlock Width="150" Text="{Binding DabActivityDate}" />
                                <TextBlock Width="100" Margin="20,0,0,0" Text="{Binding BegBalance}" />
                                <TextBlock Width="100" Margin="20,0,0,0" Text="{Binding ChrgAmount}" />
                                <TextBlock Width="100" Margin="20,0,0,0" Text="{Binding AdjAmount}" />
                                <TextBlock Width="100" Margin="20,0,0,0" Text="{Binding PmtAmount}" />
                                <TextBlock Width="100" Margin="20,0,0,0" Text="{Binding EndBalance}" />
                            </StackPanel>
                        </StackPanel>

                </HierarchicalDataTemplate>
                <DataTemplate x:Key="TestChild">
                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
                            <TextBlock Text="YOU IZ GOOD" />
                     </StackPanel>
                </DataTemplate>
                </TreeView.Resources>
            </TreeView>
        </Grid>
    </Grid>
</Window>

Код моего главного окна:

using Client_Invoice_Auditor.CoreClientAR;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Client_Invoice_Auditor
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        public string accountFile;
        public MainWindow()
        {
            InitializeComponent();
            OpenAccountFile();
        }

        private void OpenAccountFile()
        {
            accountFile = "";
            //errorFilters.Clear();
            // Displays an OpenFileDialog so the user can select a file.  
            Microsoft.Win32.OpenFileDialog openFileDialog1 = new Microsoft.Win32.OpenFileDialog();
            openFileDialog1.Filter = "Account Files|*.acct";
            openFileDialog1.Title = "Select an account file";

            if (openFileDialog1.ShowDialog() == true)
            {
                // Assign the cursor in the Stream to the Form's Cursor property.
                accountFile = openFileDialog1.FileName;

                //openFileDialog1.Dispose();
            }
            if (accountFile == "")
            {
                /*System.Windows.MessageBox.Show("File must be selected in order to continue - exiting now."
                    , "No File Selected", MessageBoxButton.OK);
                this.Close();*/
                if (!AcctDesc.HasContent)
                {
                    AcctDesc.Content = "No account file Loaded";
                    //Version version = Assembly.GetExecutingAssembly().GetName().Version;

                }
            }
            else
            {
                //openFileDialog1 = null;
                Console.WriteLine("Account file path is: " + accountFile);

                DataTable dataAR = new DataTable();

                try
                {
                    Tuple<accountARHeader, List<dailyAccountBalance>, DataTable> loadedAR = dabARLoader.LoadARData(accountFile);
                    //dataAR = loadedAR.Item2;
                    AccountNumber.Content = "Account Number: " + loadedAR.Item1.AccountNumber;
                    AcctDesc.Content = "Description: " + loadedAR.Item1.AccountDescription;
                    Organization.Content = "Client Organization: " + loadedAR.Item1.OrganizationName;
                    //TreeViewItem dummy = new TreeViewItem();
                    //dummy.DataContext = "Hi";
                    //loadedAR.Item2.First().Dummy.Add("La");
                    //DABView.Items.Add(dummy);
                    DABView.ItemsSource = loadedAR.Item2;

                    //DABView.DisplayMemberPath = "A";
                }
                catch (Exception e)
                {
                    System.Windows.MessageBox.Show("I don't wanna open this file! Try another. Error: " + e.Message);
                    OpenAccountFile();
                }

            }
        }

        private void menuOpenFile_Click(object sender, RoutedEventArgs e)
        {
            OpenAccountFile();
        }

        private void menuExit_Click(object sender, RoutedEventArgs e)
        {
            Close();
        }

        private void about_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.MessageBox.Show("I heard you like clicking buttons.");
        }
    }
}

И, наконец, мой соответствующий файл класса:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace Client_Invoice_Auditor.CoreClientAR
{
    public class dailyAccountBalance
    {
        double dabID;

        DateTime dabActivityDate;

        double begBalance;

        double endBalance;

        double chrgAmount;

        double adjAmount;

        double pmtAmount;

        string dabActivitySegment;

        public double DabID { get => dabID; set => dabID = value; }
        public double BegBalance { get => begBalance; set => begBalance = value; }
        public double EndBalance { get => endBalance; set => endBalance = value; }
        public string DabActivitySegment { get => dabActivitySegment; set => dabActivitySegment = value; }
        public DateTime DabActivityDate { get => dabActivityDate; set => dabActivityDate = value; }
        public double ChrgAmount { get => chrgAmount; set => chrgAmount = value; }
        public double AdjAmount { get => adjAmount; set => adjAmount = value; }
        public double PmtAmount { get => pmtAmount; set => pmtAmount = value; }

        public ObservableCollection<dailyAccountBalance> Items { get; set; }
        public List<string> Dummy { get => dummy; set => dummy = value; }
        public IList<TreeViewItem> DummyItems { get => dummyItems; set => dummyItems = value; }

        public dailyAccountBalance()
        {
            this.Items = new ObservableCollection<dailyAccountBalance>();
        }

        List<string> dummy = new List<string>();

        IList<TreeViewItem> dummyItems;
    }
}

Есть ли способ, например, чтобы я мог показывать фиктивную строку как ОДНОГО потомка в TreeView, когда она расширяется? Нужно ли реализовывать методы расширения для этого?

Большое спасибо заранее.

1 Ответ

0 голосов
/ 02 ноября 2018

Как правило, в прошлом я добавлял DummyNode к TreeNode, связывал свойство TreeViewItem «IsExpanded» в стиле TreeViewItem со свойством IsExpanded в моем классе Node в моей модели представления и добавлял флаг bool _isLoaded. , Затем, когда IsExpanded сработал, я проверяю, является ли _isLoaded истиной, а если нет, то иду и загружаю все последующие данные и устанавливаю для _isLoaded значение true.

Кстати ... Я использую Prism, чтобы дать мне свой класс BindableBase, который реализует событие INotifyPropertyChanged для OnPropertyChanged. Вы можете реализовать это самостоятельно вместо использования BindableBase.

Пример: Класс узла

public class TreeData : BindableBase
{
    private bool _isExpanded = false;
    private bool _isSelected = false;
    private bool _hasChildren = false;
    private Func<List<TreeData>> _getChildrenMethod;
    private bool _isLoaded = false;

    public TreeData(string value, bool hasChildren, Func<List<TreeData>> getChildren)
    {
        Value = value;
        _hasChildren = hasChildren;
        _getChildrenMethod = getChildren;

        if(hasChildren)
        {
            Children.Add(new TreeNode("Dummy", false, null));
        }
    }

    public ObservableCollection<TreeData> Children { get; set; } = new ObservableCollection<TreeData>();
    public string Value {get;set;}

    public bool IsSelected
    {
       get { return _isSelected; }
       set { _isSelected = value; OnPropertyChanged(); }
    }

    public bool IsExpanded
    {
        get { return _isExpanded; }
        set
        {
             _isExpanded = value;

             if(!_isLoaded)
             {
                 // Call load method here
                 if(_addChildrenMethod != null && _hasChildren)
                 {
                     Children.Clear();
                     Children.AddMany(_addChildrenMethod());
                 }
                 _isLoaded = true;
             }

             OnPropertyChanged();
        }
    }
}

Просмотр модели класса (владеет списком предметов)

public class BusinessViewModel
{
    public ObservableCollection<TreeData> Items { get; set; } = new ObservableCollection<TreeData>();

    public BusinessViewModel()
    { 
        Items.Add(new TreeData("Root Item", hasChildren: true, GetChildren));
    }

    public List<TreeData> GetChildren()
    {
        return new List<TreeData>()
        {
            new TreeData("Child", hasChildren: false, null);
        };
    }
}

Тогда XAML

<TreeView ItemSource="{Binding Items}" >
  <TreeView.Resources>          
      <Style TargetType="TreeViewItem">
         <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
         <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
         <Style.Triggers>
             <Trigger Property="IsSelected" Value="True">
                 <Setter Property="Background" Value="Blue" />
                 <Setter Property="Foreground" Value="White" />
             </Trigger>
         </Style.Triggers>
     </Style>
  </TreeView.Resources>
</TreeView>

Надеюсь, это поможет: D

...