类中断绑定中的逻辑

ConsKa

知名会员
已加入
2020年12月11日
留言内容
85
编程经验
Beginner
因此,经过一番争吵之后,我设法编写了一些代码,使我可以读取文本文件,将其拆分并放置到一个数组中,然后将该数组绑定到文本框中-这不是很好,因为有60个数组中的条目,然后将它们拆分到文本框中是很痛苦的-但它可以工作。我能够使用文本文件中的正确数据填充所有文本框,并且文本文件中的数字不会更改-始终为60。

C#:
List<string> Entries = new List<string>();

string DS1 = fn.CombinedName("DataSet1.txt");

            if (File.Exists(DS1))
            {
                var lines = File.ReadAllLines(DS1);
                
                Entries= lines.SelectMany(x => x.Split(new[]
                {
                    ','
                }, StringSplitOptions.None)).ToList();
            
            }            
TimeKeeper.DataContext = this;

然后,我可以将文本框绑定到xaml的输出中,如下所示:

C#:
Text="{Binding Entries [0]}"
Text="{Binding Entries [5]}"

所有这些都在名为TimeKeeper的网格中。

每行有5个条目,所以0&5是x的第一个,然后是x的第二个。

因此,我尝试遵循正确的过程,而不是在主窗口代码中进行设置,而是创建了一个类,并将逻辑放在该类中。

C#:
public class DataCollection
    {
        public List<string> Populate { get; set; }
        FileName fn = new FileName();

        public List<string> Entries()
        {
            string DS1 = fn.CombinedName("DataSet1.txt");

            if (File.Exists(DS1))
            {
                var lines = File.ReadAllLines(DS1);
                
                Populate = lines.SelectMany(x => x.Split(new[]
                {
                    ','
                }, StringSplitOptions.None)).ToList();
            }
            return Populate;
        }
    }

然后在主窗口中

C#:
List<string> Entries = new List<string>();

private void Reload()
        {
            DataCollection dc = new DataCollection();
            dc.Entries();

            Entries = dc.Populate;

            TimeKeeper.DataContext = Entries;
        }

使用断点,我可以看到Entries具有60个应该具有的条目,并且绑定是相同的-我只是不知道为什么它不起作用。我试过了

C#:
TimerKeeper.DataContext = this;

和以前一样,但这也不起作用。

在将逻辑移到类后,我是否缺少现在需要绑定的内容?
 

约翰·H

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
1,028
地点
挪威
编程经验
10+
奇怪的命名属性Populate和方法Entries,可能应该相反。

绑定用于{DataContext} .Entries,因此您设置为DataContext的对象应该具有Entries属性。
If using the 清单as DataContext you can do {Binding [0]}
 

ConsKa

知名会员
已加入
2020年12月11日
留言内容
85
编程经验
Beginner
奇怪的命名属性Populate和方法Entries,可能应该相反。

绑定用于{DataContext} .Entries,因此您设置为DataContext的对象应该具有Entries属性。
If using the 清单as DataContext you can do {Binding [0]}
谢谢,将尝试-尝试过,它可以工作-谢谢。我想我也理解为什么,只需将List定义到TimeKeeper上,这样就不需要在绑定中重新定义它,因为它知道它已经存在。

当我尝试不同的方法来尝试寻找解决方案时,我的命名约定通常会瓦解,事情会四处移动,然后重命名,因为这里的东西不存在,而我在这里需要新的东西...。我通常回头再重新一旦一切正常,就可以为它们命名,这样一个月内阅读后,我就可以更轻松地了解它们。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
出于好奇:为什么将数据集中的所有行组合到一个由60个项目组成的单一一维数组中,却将数据显示为5个项目的12行?

文件中的数据是否已经以12行5逗号分隔的形式出现?

5列和12行的意义是什么?是否可以在数据网格或列表视图中更好地呈现此数据?
 

ConsKa

知名会员
已加入
2020年12月11日
留言内容
85
编程经验
Beginner
出于好奇:为什么将数据集中的所有行组合到一个由60个项目组成的单一一维数组中,却将数据显示为5个项目的12行?

文件中的数据是否已经以12行5逗号分隔的形式出现?

5列和12行的意义是什么?是否可以在数据网格或列表视图中更好地呈现此数据?
我将文件创建为12行,每行5个逗号分隔。该文件最初是12行,每行4个逗号-全部空白。

添加和删​​除项目,但不一定按顺序进行。因此,项目1在那,项目2被删除,项目3在那。我需要它以相同的顺序加载,包括空白。通过使用逗号分隔的文件,我可以包含空格。我不确定是否可以使用其他任何方法来做到这一点?

文本文件中的5列分别对应于UI上的TextBox,其中有12行5文本框,这些文本框由用户填充-逻辑上填充-这些文本框是12个“保存”空间,每个空间都有对应的按钮。这样用户就可以从十二个保存的空间之一中调出数据,而不必再次输入所有数据,并且该逻辑将应用于该选择,将逻辑添加到先前的逻辑结果中。

UI的另一端还有12个按钮,以便用户可以删除一个项目(如果达到12个并需要添加新的,最新的项目),但是不必按顺序删除它们,所以可以从12中选择第7项,这将在文件的第7行中创建一个空白。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
因此,一行5项没有任何实际意义,除了您的UI碰巧每行有5项。除了您的UI也恰好有12行之外,还有12行也没有任何实际意义。
 

ConsKa

知名会员
已加入
2020年12月11日
留言内容
85
编程经验
Beginner
因此,一行5项没有任何实际意义,除了您的UI碰巧每行有5项。除了您的UI也恰好有12行之外,还有12行也没有任何实际意义。
那么,UI取决于所收集的数据-唯一ID,作业代码,名称,描述,时间。

12的大小实际上取决于我可以舒适地放置在表格上的数量,并且用户可以握住手柄并轻松找到他们想要的东西。
 

ConsKa

知名会员
已加入
2020年12月11日
留言内容
85
编程经验
Beginner
您可以使用这些属性快速上课,并设置一个网格,如下所示: 带有GridView的ListView-完整的WPF教程
我目前不知道如何在WPF中进行复制的功能之一是,在WinForms中,只需按一下按钮(最大化/最小化)即可更改表单大小。默认情况下,它仅显示召回按钮和1个文本框(唯一ID)以及数据输入框-这就是大多数时间的用法。

其余部分实际上是不可见的,直到您最大化表单为止,此时可以看到表单的其余部分。只是为了使其小而简洁。

我假设如果使用网格视图,我将获得将网格视图限制为一列的代码,然后在最大化时将显示其余列。

鉴于另一个功能正在使表单工作时最小化,这可能不是一个坏主意-我已经在WPF中通过隐藏主表单并打开所需的最小大小的辅助表单来进行复制。
 

ConsKa

知名会员
已加入
2020年12月11日
留言内容
85
编程经验
Beginner
对于编辑DataGrid控件可能更合适,但是该链接只是用于定义结构化类的指针,而不是列表中的匿名字符串。

我还根据以下回答考虑了字典 @跳伞 针对数据网格问题给出了不同的线索。

我认为可能符合我的目的。虽然大声笑一次一次
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
考虑到我们的OP希望能够编辑字段值(这就是为什么他在其他线程上谈论在WinForms中钩挂60个不同的文本框的原因),我认为DataGrid比ListView的GridView更合适。

这是来自同一地点的有关使用DataGrid的教程:
 

ConsKa

知名会员
已加入
2020年12月11日
留言内容
85
编程经验
Beginner
考虑到我们的OP希望能够编辑字段值(这就是为什么他在其他线程上谈论在WinForms中钩挂60个不同的文本框的原因),我认为DataGrid比ListView的GridView更合适。

这是来自同一地点的有关使用DataGrid的教程:
谢谢。

您可以在这两个位置中都存储空白,而不是在VS附近进行测试吗?

我这样做的原因之一是由于在启动应用程序时需要加载数据。为了避免浪费一天的时间,每次您按“输入”按钮时,它将写入文本文件。考虑到它读取和写入文本文件的速度,这实际上不是问题(数据大小很小)。

还有一个问题是有12个以上的项目-我正在使用一个复杂的过程来编写两个文本文件,然后从一个文件中删除,因此合并后我将拥有所有条目,无论创建的数字是多少,因为DataSetOne最多有12行。

我将不得不阅读以了解如何使该过程合并到DataGrid甚至是List View中。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
如果在单元格中放入空格,则绑定在其后面的属性将在其中存储一个空字符串。取决于您的代码将数据存储回文本文件中,以确保在序列化数据时也记下该事实。如果您将数据持久化为JSON,则序列化和反序列化都不会成为问题 @谢平 过去已经推荐了(毕竟,JSON文件是文本文件),但是正如我记得的那样,您坚持认为它必须是文本文件,并且以某种方式将其定为逗号分隔的文件,但是我不赞成完全记得原因。
 

ConsKa

知名会员
已加入
2020年12月11日
留言内容
85
编程经验
Beginner
似乎我不太可能坚持使用某些东西,除非另有建议-我通常会遵循此处给出的关于编码的建议-我可能会错过它,但这是我第一次听说存储数据在JSON文件中。我将看一下存储在JSON文件中的优点。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
我现在可能会感到困惑和错误。我正在低烧。可能有人正在与您尝试在一个文本文件中读取数据并在其WinForms控件上获取分配给特定控件的数据的旅程相同。

再次感谢您给WPF一次尝试!最初的学习曲线比WinForms的学习曲线要​​陡峭,但是您从学习中学到的技术和心态将导致更加整洁和模块化的体系结构。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
正如我在另一个线程中提到的,一些示例代码用于使用数据绑定进行加载,而无需引用任何控件。下面,我将数据绑定到DataGrid中:
MainWindow.xaml:
<Window x:Class="WpfDataGrid.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:WpfDataGrid"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <DataGrid Grid.Row="0" ItemsSource="{Binding Jobs}" />

        <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="5">
            <Button Command="{Binding LoadCommand}" Margin="5">Load</Button>
            <Button Command="{Binding SaveCommand}" Margin="5">Save</Button>
        </StackPanel>
    </Grid>
</Window>

MainWindow.xaml.cs:
using System;
using System.Collections.Generic;
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 WpfDataGrid
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainViewModel(new JobsRepository());
        }
    }
}

Job.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpfDataGrid
{
    class Job
    {
        public string Id { get; set; }
        public string Code { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public string Time { get; set; }
    }
}

JobsRepository.cs:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpfDataGrid
{
    class JobsRepository
    {
        const string JobsFile = "DataSet1.json";

        public bool DoesJobsFileExists()
            => File.Exists(JobsFile);

        public IEnumerable<Job> LoadJobs()
        {
            if (!DoesJobsFileExists())
                return new List<Job>();

            var json = File.ReadAllText(JobsFile);
            var jobs = JsonConvert.DeserializeObject<List<Job>>(json);
            return jobs;
        }

        public void SaveJobs(IEnumerable<Job> jobs)
        {
            var json = JsonConvert.SerializeObject(jobs, Formatting.Indented);
            File.WriteAllText(JobsFile, json);
        }
    }
}

MainWindowViewModel.cs:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace WpfDataGrid
{
    class MainViewModel : INotifyPropertyChanged
    {
        JobsRepository _jobsRepository;
        ObservableCollection<Job> _jobs;

        public ObservableCollection<Job> Jobs
        {
            get { return _jobs; }
            set { _jobs = value; NotifyPropertyChanged(); }
        }

        public ICommand LoadCommand { get; }
        public ICommand SaveCommand { get; }

        public event PropertyChangedEventHandler PropertyChanged;

        public MainViewModel(JobsRepository jobsRepository)
        {
            _jobsRepository = jobsRepository;

            LoadCommand = new RelayCommand(
                    p => Jobs = new ObservableCollection<Job>(_jobsRepository.LoadJobs()),
                    p => _jobsRepository.DoesJobsFileExists()
                );
            SaveCommand = new RelayCommand(p => jobsRepository.SaveJobs(Jobs));

            Jobs = new ObservableCollection<Job>(_jobsRepository.LoadJobs().ToList());

        }

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

RelayCommand.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace WpfDataGrid
{
    public class RelayCommand : ICommand
    {
        private Action<object> _execute;
        private Func<object, bool> _canExecute;

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
        {
            this._execute = execute;
            this._canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
            => _canExecute == null || _canExecute(parameter);

        public void Execute(object parameter)
            => _execute(parameter);
    }
}

它是开发人员的用户界面,因此无需多说,因为这里的主要重点是如何进行数据绑定,而不是WPF样式。

The key takeaway here is that each row on the DataGrid represents a Job object. The logic for loading and saving the list of Jobs falls on the JobsRepository class which just uses Newtonsoft's JSON.NET Nuget library. The MainViewModel takes care of coordinating loading stuff into the UI (hence the INotifyPropertyChanged implementation to notify the UI that the Jobs property might have changed), or routing commands to the repository for loading or saving data.

首次运行该程序时,它将以一个空行开始,但是您可以快速创建12个空行,然后单击“保存”按钮。下次运行该程序时,如果找到数据文件,它将自动加载它。

Screenshot_1.png
 

ConsKa

知名会员
已加入
2020年12月11日
留言内容
85
编程经验
Beginner
感谢您抽出宝贵的时间来写。

我已经读了很多书,并看了一些教程,并且我开始对一般情况有了更好的了解-我认为这是第一步-语法并不是我所看到的真正困难它(毕竟只是记住单词和含义,而这只需要时间),确实可以按预期的方式进行操作-非常感谢您将其写出来,以便可以在我正在做的事情中看到。

我认识到您已经在上面起草了某些部分-在其他情况下也看到了它们-最近观看了一个非常有用的教程,虽然它不是一个独立的教程,但它确实设法将我已经学习的几件事整合在一起关于上面的代码中复制的内容。

我确实设法破坏了您的代码,因为我相信您已经急忙将它们放在一起,并且没有添加访问修饰符,只是发现没有……他们需要私有-我将public添加到类中,我不确定为什么会这样,需要进行一些调查。

我启动并运行它,然后去上班-是的,在星期天,但是稍后将倾倒它,以便更好地了解它。

再次感谢。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
在C#中,如果未指定访问修饰符,则该成员或类型被视为私有。我记得,唯一的例外是接口成员,默认情况下是公共的。我认为某些较新的C#7或8类型默认情况下可能具有某些公共属性。
 

ConsKa

知名会员
已加入
2020年12月11日
留言内容
85
编程经验
Beginner
我知道访问修饰符默认为私有,这就是为什么我将其改为公开的原因,以为您只是简单地省略了它以完成工作-我知道您感觉不佳-但是如果将它们公开则会中断,并说不一致辅助功能。

这也是由于我在课堂上的所有学习,所以每个人所做的第一件事就是公开授课。……我想是出于示范目的……但是对于新手来说,很容易指出课堂应该是公开的。

我猜想,如果您需要将其公开,则可以遍历并更改这些部分的所有可访问性-但可以按您编写的方式工作...
 
最佳 底部