2017-07-19 55 views
1

所以基本上我想要一个动态添加新行的控件,其中每行代表我正在执行的操作。为了实现这一目标,我创建一个文本框,像这样的:视觉报告progs

<TextBox Grid.Row="1" Text="{Binding CurrRow}" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible" AcceptsReturn="True"/> 

,我更新我的视图模型的CurrRow属性如下:

for (index = 0; index < 100; index++) 
{ 
    CurrRow = CurrRow + index.ToString(); 
    //various operation 
    CurrRow = CurrRow + Environment.NewLine; 
} 

这些仅仅是一个给这个想法的例子。输出是我的预期。不过,我希望从视觉角度来看不太“静态”。例如,我想在表示当前正在工作的操作的行中添加动画“...”,并且我不知道TextBox是否在此上下文中是正确选择的。所以我的问题是:如何在WPF中创建“报表查看器”?

+1

你有没有想过用的' ListView'?将CurrRow更改为字符串列表或您需要的任何内容,并随时添加项目。 Befopre插入一个新的有效信息,删除一个包含“...”的信息,这样它将显示任务进度。 – XAMlMAX

回答

1

下面是一个使用一些库一个MVVM例子,我个人建议:

Visual report progress demo demo

视图模板(XAML只):

<Window 
    x:Class="Sandbox.Test" 
    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:local="clr-namespace:Sandbox" 
    xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    Title="Test" 
    mc:Ignorable="d"> 
    <Window.Resources> 
     <ResourceDictionary> 
      <ResourceDictionary.MergedDictionaries> 
       <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.ProgressBar.xaml" /> 
       <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Button.xaml" /> 
       <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.CheckBox.xaml" /> 
       <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.ListBox.xaml" /> 
       <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.PopupBox.xaml" /> 
       <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.RadioButton.xaml" /> 
       <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.TextBlock.xaml" /> 
       <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.ToggleButton.xaml" /> 
      </ResourceDictionary.MergedDictionaries> 
     </ResourceDictionary> 

    </Window.Resources> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="*" /> 
      <RowDefinition Height="Auto" /> 
     </Grid.RowDefinitions> 
     <ScrollViewer VerticalScrollBarVisibility="Auto" Grid.Row="0"> 
      <ItemsControl 
       MaxWidth="300" 
       Margin="16,8" 
       ItemsSource="{Binding LongTasks}"> 
       <ItemsControl.ItemTemplate> 
        <DataTemplate> 
         <ContentControl Content="{Binding}"> 
          <ContentControl.Style> 

           <Style TargetType="{x:Type ContentControl}"> 
            <Style.Triggers> 
             <DataTrigger Binding="{Binding IsFinished}" Value="False"> 
              <DataTrigger.Setters> 
               <Setter Property="ContentTemplate"> 
                <Setter.Value> 
                 <DataTemplate> 
                  <DockPanel Margin="12"> 
                   <ProgressBar 
                    HorizontalAlignment="Center" 
                    VerticalAlignment="Center" 
                    DockPanel.Dock="Right" 
                    Style="{StaticResource MaterialDesignCircularProgressBar}" 
                    Value="{Binding Progress}" /> 
                   <TextBlock 
                    VerticalAlignment="Center" 
                    Style="{StaticResource MaterialDesignDisplay1TextBlock}" 
                    Text="Task running" /> 
                  </DockPanel> 
                 </DataTemplate> 

                </Setter.Value> 
               </Setter> 
              </DataTrigger.Setters> 
             </DataTrigger> 
            </Style.Triggers> 
            <Setter Property="ContentTemplate"> 
             <Setter.Value> 
              <DataTemplate> 
               <TextBlock 
                Margin="12" 
                VerticalAlignment="Center" 
                Style="{StaticResource MaterialDesignDisplay1TextBlock}" 
                Text="Task finished" /> 
              </DataTemplate> 
             </Setter.Value> 
            </Setter> 
           </Style> 
          </ContentControl.Style> 
         </ContentControl> 
        </DataTemplate> 
       </ItemsControl.ItemTemplate> 

      </ItemsControl> 
     </ScrollViewer> 
     <Button 
      Grid.Row="1" 
      Margin="12" 
      HorizontalAlignment="Right" 
      Command="{Binding AddLongTask}" 
      Content="{materialDesign:PackIcon Kind=Plus, 
               Size=32}" 
      Style="{StaticResource MaterialDesignFloatingActionButton}" /> 
    </Grid> 
</Window> 

```

关键点在这里你似乎想要的是使用DataTrigger根据您的情况更改ContentControlContentTemplate所以你可以展示完全不同的东西。

视图模型来模拟从长远来看,任务背景:

using System; 
using System.Reactive.Linq; 
using System.ComponentModel; 
using System.Linq.Expressions; 
using System.Runtime.CompilerServices; 
using System.Windows.Input; 
using System.Collections.ObjectModel; 

namespace Sandbox 
{ 

    public class SandboxNotifiableViewModel : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 

     public void RaisePropertyChanged<TProperty>(Expression<Func<TProperty>> projection) 
     { 
      var memberExpression = (MemberExpression) projection.Body; 
      this.RaisePropertyChanged(memberExpression.Member.Name); 
     } 

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

    public class TestViewModel : SandboxNotifiableViewModel 
    { 
     private class SandBoxCommand : ICommand 
     { 
      private readonly Action cbk; 
      public event EventHandler CanExecuteChanged; 

      private void WarningRemover() 
       => this.CanExecuteChanged?.Invoke(this, EventArgs.Empty); 

      public SandBoxCommand(Action cbk) 
      { 
       this.cbk = cbk; 
      } 

      public bool CanExecute(object parameter) 
       => true; 
      public void Execute(object parameter) 
       => this.cbk?.Invoke(); 
     } 

     public TestViewModel() 
     { 
      this.AddLongTask = new SandBoxCommand(this.AddLongTaskAction); 
      this.LongTasks = new ObservableCollection<LongTaskViewModel>(); 
     } 

     public ObservableCollection<LongTaskViewModel> LongTasks { get; } 

     private void AddLongTaskAction() 
      => this.LongTasks.Add(new LongTaskViewModel()); 

     public ICommand AddLongTask { get; } 
    } 

    public class LongTaskViewModel : SandboxNotifiableViewModel 
    { 
     private bool isFinished; 
     private int progress; 


     public LongTaskViewModel() 
     { 
      this.Progress = 0; 
      this.IsFinished = false; 
      // Refresh progress every 10ms 100 times 
      Observable.Interval(TimeSpan.FromMilliseconds(10)) 
       .Select(x => x + 1) // 1 to 100 
       .Take(100) 
       // Here we make sure observable callback is called on dispatcher thread 
       .ObserveOnDispatcher() 
       .SubscribeOnDispatcher() 
       .Subscribe(this.OnProgressReported, this.OnLongTaskFinished); 
     } 

     public bool IsFinished 
     { 
      get => this.isFinished; 
      set 
      { 
       this.isFinished = value; 
       this.RaisePropertyChanged(); 
      } 
     } 

     public int Progress 
     { 
      get => this.progress; 
      set 
      { 
       this.progress = value; 
       this.RaisePropertyChanged(); 
      } 

     } 

     public void OnProgressReported(long dummyval) 
     { 
      this.Progress = (int) dummyval; 
     } 

     public void OnLongTaskFinished() 
     { 
      this.IsFinished = true; 
     } 
    } 
} 

我以前Rx.NET处理异步通知(这里进度模拟)和MaterialDesignInXamlToolkit全球造型