繁体   English   中英

Wpf中如何给子元素添加倒数计时器

[英]How to add a countdown timer to a child element in Wpf

我对编码很陌生。 到目前为止,我有一个 WPF 应用程序,当我按下提交时,它会创建 treeview 但我想为每个子项添加一个倒数计时器,并让它显示子项旁边的剩余时间。 问题是 treeview 没有更新,我不知道如何为每个子项目分配一个计时器

using Microsoft.Azure.Cosmos.Core.Collections;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
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;
using System.Windows.Threading;

namespace Test_v2
{


    public partial class MainWindow : Window
    {
        public int secondsCount = 100;
        public MainWindow()
        {
            InitializeComponent();
            DispatcherTimer disTmr = new DispatcherTimer();
            disTmr.Tick += new EventHandler(disTmr_Tick);
            disTmr.Interval = new TimeSpan(0, 0, 1);
            disTmr.Start();
        }
        public void disTmr_Tick(object sender, EventArgs e)
        {
            secondsCount--;
        }

        List<TreeViewItem> folderList = new List<TreeViewItem>();
        public void SubmitButton_Click(object sender, RoutedEventArgs e)
        {
            
            if (Folder.Text.Length == 0)
            {
                ErrorBlock.Text = "Please Enter Folder Name";
                return;
            }
            if (Name.Text.Length == 0)
            {
                ErrorBlock.Text = "Please Enter a Name";
                return;
            }

            TreeViewItem parent = new TreeViewItem();
            
            for (int i = 0; i < folderList.Count; i++)
            {
                if (folderList[i].Header.ToString() == Folder.Text)
                {
                    parent = folderList[i];
                    break;
                }
            }

            if (folderList.Contains(parent))
            {
               
                FolderInArrayBlock.Text = "True";
                TreeViewItem newChild = new TreeViewItem();
                newChild.Header = Name.Text + secondsCount.ToString();
                parent.Items.Add(newChild);
                
            }
            else
            {
                FolderInArrayBlock.Text = "false";
                TreeViewItem? treeItem = null;
                treeItem = new TreeViewItem();
                treeItem.Header = Folder.Text;
                folderList.Add(treeItem);
                treeItem.Items.Add(new TreeViewItem() { Header = Name.Text + secondsCount.ToString()});
                LearningItems.Items.Add(treeItem);
            }
  
        
        }
        
    }
}
    

首先,如果你使用的是 Wpf,如果你想制作一个可持续和可维护的代码,你需要使用MVVM方法。 这意味着您需要将 View 功能与 Model 功能分开,并使用 ViewModel 作为桥梁,以便能够与这两个功能进行通信。 在 Wpf 中,我们应该尝试使用 Bindings 和 notifypropertychange 来构建 View 和 ViewModel 之间的桥梁,而不是使用控件命名以供以后在代码 behind.cs 中使用。(代码 behind 是属于 .xaml 文件的 .cs 文件 ex.:MainWindow .xaml.cs)

我建议您查看此页面,它解释了为什么在 Wpf 应用程序中使用 MVVM 如此重要: MVVM 模式

在我看来,我已经创建了一个示例项目,它展示了适合您的任务的方法。

主窗口.xaml

<Window x:Class="TreeViewWithCountDown.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:TreeViewWithCountDown"
    xmlns:localviewmodels="clr-namespace:TreeViewWithCountDown.ViewModels"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<Grid>
    <TreeView ItemsSource="{Binding Path=Items, Mode=OneWay}">

        <!--We use TreeView Resources because we bind Items as ItemSource and Items is a List of StorageItems, which can be either FolderItem or FileItem.
            TreeView can display the two types differently if we specify in the Resources-->
        <TreeView.Resources>
            <!--Here we specify how to display a FolderItem-->
            <HierarchicalDataTemplate DataType="{x:Type localviewmodels:FolderItem}"
                                      ItemsSource="{Binding Path=Items}">
                <TextBlock Text="{Binding Path=Name}"
                               Margin="0 0 35 0"/>
            </HierarchicalDataTemplate>

            <!--Here we specify how to display a FileItem-->
            <DataTemplate DataType="{x:Type localviewmodels:FileItem}">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" SharedSizeGroup="FileNames"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="{Binding Path=Name}"
                                       Margin="0 0 35 0"
                                       Grid.Column="0"/>
                    <TextBlock Text="{Binding Path=CountdownTime}"
                                       Margin="0 0 15 0"
                                       Grid.Column="1">
                    </TextBlock>
                </Grid>
            </DataTemplate>
        </TreeView.Resources>
    </TreeView>
</Grid>

MainWindow.xaml.cs

using System.Windows;
namespace TreeViewWithCountDown
{
   public partial class MainWindow : Window
   {
       private ViewModel _viewModel= new ViewModel();

       public MainWindow()
       {
           InitializeComponent();

           //Really important to define where to look for the binding properties
           DataContext = _viewModel;
        }
    }
}

ViewModel.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Timers;
using TreeViewWithCountDown.ViewModels;

namespace TreeViewWithCountDown
{
public class ViewModel : INotifyPropertyChanged
{
    private List<StorageItem> _items = new List<StorageItem>();
    public List<StorageItem> Items
    {
        get => _items;
        set
        {
            if (_items != value)
            {
                _items = value;
                OnPropertyChanged();
            }
        }
    }

    public ViewModel()
    {
        //Filling up our Items property which will be given to the View for display
        Random random = new Random();
        FileItem item0 = new FileItem("file0", random.Next(0,100));
        FolderItem item1 = new FolderItem("folder1");
        item1.Items.Add(item0);

        FileItem item2 = new FileItem("file2", random.Next(0, 100));
        FileItem item3 = new FileItem("file3", random.Next(0, 100));


        Timer timer = new Timer(3000);
        timer.Elapsed += Time_Elapsed;
        timer.Start();

        Items.Add(item1);
        Items.Add(item2);
        Items.Add(item3);
    }

    private void Time_Elapsed(object sender, ElapsedEventArgs e)
    {
        foreach (StorageItem item in Items) 
        {
            if (item is FileItem fileItem)
            {
                fileItem.CountdownTime--;
            }
            else
            {
                //Reducing counters of Files in Folders
                ReduceFileCountInFolders(item);
            }
        }
    }

    //A file can be nested in multiple folders so we can solve this with a recursive method
    private void ReduceFileCountInFolders(StorageItem item)
    {
        if (item is FileItem fileItem)
        {
            fileItem.CountdownTime--;
        }
        else if (item is FolderItem folderItem)
        {
            if (folderItem.Items != null && folderItem.Items.Count > 0) 
            {
                foreach (StorageItem storageItem in folderItem.Items) 
                { 
                    ReduceFileCountInFolders(storageItem);
                }
            }
        }
    }

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        try
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        catch (Exception ex)
        {
            throw new Exception($"PropertyChanged event handler FAILED : {ex.Message}");
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;

}
}

存储项.cs

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace TreeViewWithCountDown.ViewModels
{
public class StorageItem : INotifyPropertyChanged
{
    private string _name;
    public string Name 
    {
        get => _name;
        set 
        {
            if (_name != value) 
            {
                _name = value;
                OnPropertyChanged();
            }
        }
    }

    public StorageItem(string name)
    {
        Name = name;
    }

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        try
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        catch (Exception ex)
        {
            throw new Exception($"PropertyChanged event handler FAILED : {ex.Message}");
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
}
}

文件项.cs

namespace TreeViewWithCountDown.ViewModels
{
public class FileItem : StorageItem
{

    private int _countdownTime;
    public int CountdownTime
    {
        get => _countdownTime;
        set
        {
            if (_countdownTime != value && value > 0)
            {
                _countdownTime = value;
                OnPropertyChanged();
            }
        }
    }

    public FileItem(string name, int num) : base(name)
    {
        CountdownTime = num;
    }
}
}

文件夹项目.cs

using System.Collections.Generic;

namespace TreeViewWithCountDown.ViewModels
{
public class FolderItem : StorageItem
{
    private List<StorageItem> _items = new List<StorageItem>();
    public List<StorageItem> Items
    {
        get => _items;
        set 
        {
            if (_items != value)
            {
                _items = value;
                OnPropertyChanged();
            }
        }
    }

    public FolderItem(string name) : base(name)
    {

    }
}
}

最后的样子: View

希望这会有所帮助,如果有任何事情看起来很复杂,请随时提问!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM