WPF将List返回给类

时间:2015-09-29 20:23:12

标签: c# wpf

来自VB网络表单的WPF和C#的新手,很抱歉这个结构不合理的问题我将根据需要添加以改进。我试图通过向MySQL添加数据库调用来实现一个示例来填充按需树视图控件。以下是示例代码的链接......

sample code

我的数据库连接正常工作,数据正在填充我的数据集。我迭代到列表中。但似乎无法弄清楚将List传递给Class来填充控件的问题......

public class Level1
{
    public Level1(string level1Name)
    {
        this.Level1Name = level1Name;
    }

    public string Level1Name { get; private set; }

    readonly List<Level2> _level2s = new List<Level2>();
    public List<Level2> Level2s
    {
        get { return _level2s; }
    }
}

我有一个数据库类,用于查询数据库并解析数据....

List<string> level1s = new List<string>();
DataSet ds = new DataSet();

foreach (DataTable table in ds.Tables)
{
    foreach (DataRow row in table.Rows)
    {
        level1s.Add((string)row["name"]);
    }
}


**UPDATE**: Trying to return the list...

return new Level1[]
  {
  foreach(DataRow row in level1s)
  {
    // iterate here               
  }
};

我的level1s List已正确填充,我只是在返回值时画了一个空白。

感谢,

更新 - 我也在此处包含ViewModel代码....

using BusinessLib;

namespace TreeViewWithViewModelTOC.LoadOnDemand
{
    public class Level1ViewModel : TreeViewItemViewModel
    {
        readonly Level1 _level1;

        public Level1ViewModel(Level1 level1) 
            : base(null, true)
        {
            _level1 = level1;
        }

        public string Level1Name
        {
            get { return _level1.Level1Name; }
        }

        protected override void LoadChildren()
        {
            foreach (Level2 level2 in Database.GetLevel2s(_level1))
                base.Children.Add(new Level2ViewModel(level2, this));
        }
    } 
}

3 个答案:

答案 0 :(得分:1)

请尝试以下方式,

List<Level1> L1=new List<Level1>();
 foreach(var row in level1s)
 {
    Level1 L=new Level1();
    // L.Level1Name = row.ToString(); here add items as you need
    L1.Add(L);
  }
 return L1.ToArray();

答案 1 :(得分:1)

您应该使用MVVM设计模式来解决这个问题。你的问题中没有列出很多要求,所以我将自己承担,这应该引导你走上正确的道路。

首先要确定你的记录是否会在运行时准备/拉出 - 在TreeView呈现之前以及它们是否会被更改/更新/添加/删除应用程序生命周期中的结构。如果不会更改结构,您可以继续使用List作为集合。如果您(或用户)要从集合中添加/删除,最终更改结构,则需要通知UI该集合发生了更改;所以你会使用内置的ObservableCollection。这是一个MVVM纯粹的解决方案,假设您的数据将在应用程序启动时被提取,您将修改集合:

注意RelayCommand实施取自here

模型

public class First
{
    public string Name
    {
        get;
        set;
    }

    public readonly List<Second> Children;

    public First(string name)
    {
        Name = name;
        Children = new List<Second>
        {
            new Second(1),
            new Second(2),
            new Second(3),
        };
    }

    public void AddChild(Second child)
    {
        Children.Add(child);
        ChildAdded(this, new ChildAddedEventArgs(child));
    }

    public EventHandler<ChildAddedEventArgs> ChildAdded;
}
public class ChildAddedEventArgs //technically, not considered a model
{
    public readonly Second ChildAdded;
    public ChildAddedEventArgs(Second childAdded)
    {
        ChildAdded = childAdded;
    }
}
public class Second
{
    public int Number
    {
        get;
        set;
    }
    public Second(int number)
    {
        Number = number;
    }
}

的ViewModels

public class MainViewModel : INotifyPropertyChanged
{
    private readonly ObservableCollection<FirstViewModel> _items;
    private readonly ICommand _addFirstFirstChildCommand;
    private readonly ICommand _addSecondFirstChildCommand;
    private readonly ICommand _toggleExpandCollapseCommand;

    private bool _firstAddedFlag;

    public MainViewModel(IEnumerable<First> records)
    {
        _items = new ObservableCollection<FirstViewModel>();
        foreach(var r in records)
        {
            _items.Add(new FirstViewModel(r));
        }

        _addFirstFirstChildCommand = new RelayCommand(param => AddFirst(), param => CanAddFirst);
        _addSecondFirstChildCommand = new RelayCommand(param => AddSecond(), param => CanAddSecond);
        _toggleExpandCollapseCommand = new RelayCommand(param => ExpandCollapseAll(), param =>
        {
            return true;
        });
    }

    public ObservableCollection<FirstViewModel> Items
    {
        get
        {
            return _items;
        }
    }

    public ICommand AddFirstFirstChildCommand
    {
        get
        {
            return _addFirstFirstChildCommand;
        }
    }
    public ICommand AddSecondFirstChildCommand
    {
        get
        {
            return _addSecondFirstChildCommand;
        }
    }

    public ICommand ToggleExpandCollapseCommand
    {
        get
        {
            return _toggleExpandCollapseCommand;
        }
    }
    public bool CanAddFirst
    {
        get
        {
            return true;
        }
    }

    public bool CanAddSecond
    {
        get
        {
            //Only allow second to be added if we added to first, first
            return _firstAddedFlag;
        }
    }

    public void AddFirstChild(FirstViewModel item)
    {
        Items.Add(item);
    }

    private void AddFirst()
    {
        _items[0].AddChild(new Second(10));
        _firstAddedFlag = true;
    }

    private void AddSecond()
    {
        _items[1].AddChild(new Second(20));
    }

    private void ExpandCollapseAll()
    {
        foreach(var i in Items)
        {
            i.IsExpanded = !i.IsExpanded;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
public class FirstViewModel : INotifyPropertyChanged
{
    private readonly First model;
    private readonly ObservableCollection<SecondViewModel> _children;

    private bool _isExpanded;

    public FirstViewModel(First first)
    {
        _children = new ObservableCollection<SecondViewModel>();
        model = first;
        foreach(var s in first.Children)
        {
            Children.Add(new SecondViewModel(s));
        }
        model.ChildAdded += OnChildAdded;
    }

    public string FirstName
    {
        get
        {
            return model.Name;
        }
        set
        {
            model.Name = value;
            NotifyPropertyChanged();
        }
    }

    public ObservableCollection<SecondViewModel> Children
    {
        get
        {
            return _children;
        }
    }

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

    internal void AddChild(Second second)
    {
        model.AddChild(second);
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public void OnChildAdded(object sender, ChildAddedEventArgs args)
    {
        if(Children != null)
        {
            Children.Add(new SecondViewModel(args.ChildAdded));
        }
    }
}
public class SecondViewModel : INotifyPropertyChanged
{
    private readonly Second model;
    private bool _isExpanded;

    public SecondViewModel(Second second)
    {
        model = second;
    }
    public int SecondNumber
    {
        get
        {
            return model.Number;
        }
        set
        {
            model.Number = value;
            NotifyPropertyChanged();
        }
    }

    //Added property to avoid warnings in output window
    public bool IsExpanded
    {
        get
        {
            return _isExpanded;
        }
        set
        {
            _isExpanded = value;
            NotifyPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

模型提供者

public class Database
{
    public static IEnumerable<First> GetChildren()
    {
        List<First> firsts = new List<First>();
        firsts.Add(new First("John"));
        firsts.Add(new First("Roxanne"));
        return firsts;
    }
}

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    private MainViewModel mvm;

    public MainWindow()
    {
        var db = Database.GetChildren();
        mvm = new MainViewModel(db);
        InitializeComponent();

        DataContext = mvm;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        //Do not do this, example only
        var f = new First("Billy");
        mvm.AddFirstChild(new FirstViewModel(f));

        //Prove that the event was raised in First, FirstViewModel see & handles it, and
        //the UI is updated
        f.AddChild(new Second(int.MaxValue));
    }
}

MainWindow.xaml

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication2"
        Title="MainWindow">
    <Grid>
        <TreeView ItemsSource="{Binding Items}">
            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type local:FirstViewModel}" 
                                          ItemsSource="{Binding Children}">
                    <TextBlock Text="{Binding FirstName}" />
                </HierarchicalDataTemplate>
                <DataTemplate DataType="{x:Type local:SecondViewModel}">
                    <TextBlock Text="{Binding SecondNumber}" />
                </DataTemplate>
            </TreeView.Resources>
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}">
                    <Setter Property="IsExpanded"
                            Value="{Binding IsExpanded, Mode=TwoWay}" />
                </Style>
            </TreeView.ItemContainerStyle>
        </TreeView>
        <StackPanel Orientation="Vertical"
                    VerticalAlignment="Bottom">
            <StackPanel Orientation="Horizontal">
                <Button Content="Add Child to first First"
                        Command="{Binding AddFirstFirstChildCommand}" />
                <Button Content="Toggle Expand"
                        Command="{Binding ToggleExpandCollapseCommand}" />
                <Button Content="Add Child to second First"
                        Command="{Binding AddSecondFirstChildCommand}" />
            </StackPanel>
            <Button Content="Bad Codebehind Button" 
                    Click="Button_Click"/>
        </StackPanel>
    </Grid>
</Window>

答案 2 :(得分:1)

这将返回DataSet中第一个表的Level1数组(通常只有一个表)

public void Level1[] GetLevels()
{
   DataSet ds = ....
   return ds.Tables[0].Rows
       .Select(row => new Level1((string)row["name"]))
       .ToArray();
}

如果数据集中有多个表,则可以使用此方法循环遍历所有表:

public void Level1[] GetLevels()
{
   DataSet ds = ....
   return ds.Tables
       .SelectMany(t => t.Rows)
       .Select(row => new Level1((string)row["name"]))
       .ToArray();
}

第二个代码示例与问题中的代码完全相同。

了解linq非常有用。