我的数据模板未在WPF应用程序中显示来自ObservableCollection >

问题描述 投票:0回答:2

我创建了一个具有ObservableCollection的WPF应用程序>。这绑定到一个ListBox,它具有一个DataTemplate来以整洁的方式显示信息。

当我运行该应用程序时,列表框将按预期方式填充行...但数据模板中未显示任何信息。

这里是代码部分

WINDOW XAML代码

<Window
    x:Class="web.app.smash.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:local="clr-namespace:web.app.smash"
    xmlns:m="clr-namespace:web.app.smash.lib.Helpers;assembly=web.app.smash.lib"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    x:Name="MainPage"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <Window.Resources>


        <DataTemplate x:Key="ResultListItemTemplate" DataType="{x:Type m:ProcessedURLResult}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="150" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="12" />
                    <RowDefinition Height="12" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>

                <StackPanel Orientation="Horizontal">
                    <TextBlock
                        FontSize="8"
                        FontWeight="Bold"
                        Text="Start time:" />
                    <TextBlock
                        x:Name="StartTime"
                        Width="50"
                        Margin="4,0,0,0"
                        FontSize="8"
                        Text="{Binding StartTime, Mode=OneWay}" />
                </StackPanel>

                <StackPanel Grid.Row="1" Orientation="Horizontal">
                    <TextBlock
                        FontSize="8"
                        FontWeight="Bold"
                        Text="End time:" />
                    <TextBlock
                        x:Name="EndTime"
                        Margin="4,0,0,0"
                        FontSize="8"
                        Text="{Binding EndTime, Mode=OneWay}" />
                </StackPanel>

                <StackPanel Grid.Column="1" Orientation="Horizontal">
                    <TextBlock
                        FontSize="8"
                        FontWeight="Bold"
                        Text="Milli seconds:" />
                    <TextBlock
                        x:Name="MilliSecondsTaken"
                        Margin="4,0,0,0"
                        FontSize="8"
                        Text="{Binding MillisecondsTaken, Mode=OneWay}" />
                </StackPanel>

                <StackPanel
                    Grid.Row="1"
                    Grid.Column="1"
                    Orientation="Horizontal">
                    <TextBlock
                        FontSize="8"
                        FontWeight="Bold"
                        Text="HTTP ststus code:" />
                    <TextBlock
                        x:Name="HTTPStatusCode"
                        Margin="4,0,0,0"
                        FontSize="8"
                        Text="{Binding HTTPStatusCode, Mode=OneWay}" />
                </StackPanel>

                <StackPanel
                    Grid.Row="2"
                    Grid.ColumnSpan="2"
                    Orientation="Horizontal">
                    <TextBlock
                        FontSize="8"
                        FontWeight="Bold"
                        Text="Error message:" />
                    <TextBlock
                        x:Name="ErrorMessage"
                        Height="22"
                        Margin="4,0,0,0"
                        FontSize="8"
                        Text="{Binding ErrorMessage, Mode=OneWay}"
                        TextWrapping="Wrap" />
                </StackPanel>

                <StackPanel
                    Grid.Row="3"
                    Grid.ColumnSpan="2"
                    Orientation="Horizontal">
                    <TextBlock
                        FontSize="8"
                        FontWeight="Bold"
                        Text="API results" />
                    <TextBlock
                        x:Name="APIResults"
                        Height="42"
                        Margin="4,0,0,0"
                        FontSize="8"
                        Text="{Binding APIResults, Mode=OneWay}"
                        TextWrapping="Wrap" />
                </StackPanel>




            </Grid>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="32" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <StackPanel
            Grid.Row="0"
            Grid.Column="0"
            Orientation="Vertical">
            <Button
                x:Name="SubmitCustomerGet"
                Margin="0,0,0,12"
                Click="SubmitCustomerGet_Click"
                Content="Get a Customer" />
            <Button
                x:Name="StartPerformanceTests"
                Margin="0,0,0,4"
                Click="StartPerformanceTests_Click"
                Content="Start Tests" />
            <Button
                x:Name="StopPerformanceTests"
                Margin="0,0,0,4"
                Click="StopPerformanceTests_Click"
                Content="Stop Tests" />
        </StackPanel>

        <StackPanel
            Grid.Row="0"
            Grid.Column="1"
            Orientation="Vertical">
            <TextBlock x:Name="CountURLAdded" Background="#FFFBFFA7" />
            <TextBlock x:Name="CountURLWaiting" Background="#FFEA9393" />
            <TextBlock x:Name="CountURLFinished" Background="#FFB7EEB1" />
        </StackPanel>

        <TextBlock
            x:Name="InformationMessage"
            Grid.Row="1"
            Grid.ColumnSpan="2"
            Background="#FF646464" />

        <ListBox
            x:Name="ResultList"
            Grid.Row="2"
            Grid.ColumnSpan="3"
            ItemTemplate="{DynamicResource ResultListItemTemplate}"
            ItemsSource="{Binding ElementName=MainPage, Path=AwesomeSauce, Mode=OneWay}" />
    </Grid>
</Window>

隐藏窗口代码

using System;
using System.Timers;
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;
using web.app.smash.lib;
using web.app.smash.lib.Helpers;
using System.Net.Http;
using System.Threading;
using Timer = System.Timers.Timer;
using System.Diagnostics;
using System.Collections.ObjectModel;

namespace web.app.smash
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        //This is the URL to the webAPI
        private const string BASEURL = "http://localhost:23653/";


        public ObservableCollection<Task<ProcessedURLResult>> AwesomeSauce
        {
            get
            { return ocDownloadedTasks; }
            set
            { ocDownloadedTasks = value; }
        }

        private ObservableCollection<Task<ProcessedURLResult>> ocDownloadedTasks;

        private WebRequestCustomer wc = new WebRequestCustomer();
        private CancellationTokenSource cts;
        private CancellationToken ct;

        private HttpClient client = new HttpClient();

        private long counturladded = 0;
        private long counturlwaiting = 0;
        private long counturlfinihed = 0;

        private Timer smashtimer;


        public MainWindow()
        {
            Debug.WriteLine("App started");

            InitializeComponent();


            SetupTimer(1000);

            ocDownloadedTasks = new ObservableCollection<Task<ProcessedURLResult>>();

            ocDownloadedTasks.CollectionChanged += OcDownloadedTasks_CollectionChanged;

            ResultList.ItemsSource = ocDownloadedTasks;
        }

        private void OcDownloadedTasks_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            foreach(Task t in e.NewItems)
            {
                if(t.Status == TaskStatus.Created)
                {
                    t.RunSynchronously();
                }
            }
        }

        private void SetupTimer(double interval)
        {
            Debug.WriteLine("Timer set to:" + interval.ToString());

            smashtimer = new System.Timers.Timer(interval);

            Debug.WriteLine("Timer event handler set");
            smashtimer.Elapsed += Smashtimer_Elapsed;

            smashtimer.AutoReset = true;
        }

        private void Smashtimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            //Debug.WriteLine("Timer event handler elapsed start: " + e.SignalTime.ToString());
            //this.urlList.Add(BASEURL);


            //Debug.WriteLine("ProcessAll: Returns a collection of tasks (In Loop)");
            //// ***Create a query that, when executed, returns a collection of tasks.
            //TasksList = from url in this.urlList select wc.ProcessPostURL(url, client, ct);

            //Debug.WriteLine("ProcessAll: Start processing the list of Tasks (In Loop)");
            //downloadTasks.AddRange(TasksList.ToList());


            //downloadTasks.Add(wc.ProcessPostURL(BASEURL, client, ct));

            App.Current.Dispatcher.Invoke((Action)delegate
            {
                ocDownloadedTasks.Add(wc.ProcessPostURL(BASEURL, client, ct));
            });



            //TasksList = null;

            counturladded += 1;
        }

        private async void SubmitCustomerGet_Click(object sender, RoutedEventArgs e)
        {
            await wc.GetCustomerByID(BASEURL, 6);
            //ResponsesList.Inlines.Add(wc.DisplayResults);
            //ResponsesList.Inlines.Add(new LineBreak());
            InformationMessage.Text = "Get single customer";
        }

        private void StartPerformanceTests_Click(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("Start Performance button: Clicked");


            Debug.WriteLine("Start Performance button: Create the cancelation token");
            //Create the cancellation token
            cts = new CancellationTokenSource();
            ct = cts.Token;

            Debug.WriteLine("Start Performance button: Timer started");
            smashtimer.Start();


            InformationMessage.Text = "Timer Started";
        }

        private void StopPerformanceTests_Click(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("Stop performance button: Clicked");

            Debug.WriteLine("Stop performance button: Timer stopped");
            smashtimer.Stop();
            InformationMessage.Text = "Timer Stopped";
        }

        //private void DisplayResults(ProcessedURLResult pur)
        //{
        //    StringBuilder sb = new StringBuilder();

        //    if (pur.ErrorMessage==null)
        //    {
        //        sb.Append("Milliseconds: " + pur.MillisecondsTaken.ToString());
        //        sb.Append("API Result: " + pur.APIResults);


        //        ResponsesList.Inlines.Add(sb.ToString());
        //        ResponsesList.Inlines.Add(new LineBreak());

        //    }
        //    else
        //    {
        //        sb.Append("Error: " + pur.ErrorMessage);

        //        ResponsesList.Inlines.Add(sb.ToString());
        //        ResponsesList.Inlines.Add(new LineBreak());
        //    }
        //    ResponsesList.InvalidateVisual();

        //}


        //private void DisplayInformation()
        //{
        //    CountURLAdded.Text = counturladded.ToString();
        //    CountURLWaiting.Text = counturlwaiting.ToString();
        //    CountURLFinished.Text = counturlfinihed.ToString();
        //}
    }
}

PROCESSURLRESULTS CODE

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace web.app.smash.lib.Helpers
{
    public class ProcessedURLResult : INotifyPropertyChanged
    {
        private string _apiresults;
        private long _millisecondsTaken;
        private DateTime _startTime;
        private DateTime _endTime;
        private string _hTTPStatusCode;
        private string _errorMessage;

        public string APIResults
        {
            get
            {
                return _apiresults;
            }
            set
            {
                _apiresults = value;
                OnPropertyChanged(nameof(APIResults));
            }
        }

        public long MillisecondsTaken
        {
            get
            {
                return _millisecondsTaken;
            }
            set
            {
                _millisecondsTaken = value;
                OnPropertyChanged(nameof(MillisecondsTaken));
            }
        }

        public DateTime StartTime
        {
            get
            {
                return _startTime;
            }
            set
            {
                _startTime = value;
                OnPropertyChanged(nameof(StartTime));
            }
        }

        public DateTime EndTime
        {
            get
            {
                return _endTime;
            }
            set
            {
                _endTime = value;
                OnPropertyChanged(nameof(EndTime));
            }
        }

        public string HTTPStatusCode
        {
            get
            {
                return _hTTPStatusCode;
            }
            set
            {
                _hTTPStatusCode = value;
                OnPropertyChanged(nameof(HTTPStatusCode));
            }
        }

        public string ErrorMessage 
        {
            get
            {
                return _errorMessage;
            }
            set
            {
                _errorMessage = value;
                OnPropertyChanged(nameof(ErrorMessage));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        // Create the OnPropertyChanged method to raise the event
        private protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }
}

Talking Points

ObservableCollection拥有类型为ProcessURLResults的任务,要访问ProcessURLResults的这些属性,您需要使用任务的Results属性。

ocDownloadedTasks[0].Result.APIResults;

因此,如何使ListBox的DataTemplate获得Result属性?

c# wpf data-binding task observablecollection
2个回答
0
投票

我认为您的模板绑定类型不匹配。

<DataTemplate x:Key="ResultListItemTemplate" DataType="{x:Type m:ProcessedURLResult}">

与]不同>

public ObservableCollection<Task<ProcessedURLResult>> AwesomeSauce

ItemsSource="{Binding ElementName=MainPage, Path=AwesomeSauce, Mode=OneWay}" />

是多余的。您在MainWindow()中拥有分配代码

ResultList.ItemsSource = ocDownloadedTasks;

尝试使用包装器类。例如

public class ResultWrapper
{
    public Task<ProcessedURLResult> InnerTask { get; set; }

    public ProcessedURLResult Result
    {
        get
        {
            return InnerTask.Result;
        }
    }

}

public ObservableCollection<ResultWrapper> AwesomeSauce

XAML是

<DataTemplate x:Key="ResultListItemTemplate" DataType="{x:Type ResultWrapper}">
...
    <TextBlock
                    x:Name="StartTime"
                    Width="50"
                    Margin="4,0,0,0"
                    FontSize="8"
                    Text="{Binding Result.StartTime, Mode=OneWay}" />
....

0
投票

您必须将DataType更改为Task(或将其完全删除,然后调整装订路径:

© www.soinside.com 2019 - 2024. All rights reserved.