函数调用在内部从其控件内部调用时有效,但在主应用程序外部调用时无效

时间:2013-11-20 00:46:24

标签: c# wpf inotifypropertychanged

我使用了从本网站检索到的一些代码来创建滚动终端类型窗口。这个例子运行得很好,所以我决定将它变成一个基本的控件,这样我就可以重用了。 在控件中我有一个“LogEntry”类型列表,它被数据绑定到“项目控件”,所以当列表更新时,项目控件也是如此。通过调用“AddEntry”函数更新此列表。当从控件内部调用此函数时,列表会通知“ItemsControl”发生了更新。当我从主窗口调用“AddEntry()”函数时,列表会更新,但“ItemsControl”不会获得更新通知。 有谁能解释为什么? 谢谢你的帮助 问候 斯图尔特

这是用户控件的代码

TerminalWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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.Collections.ObjectModel;
using System.ComponentModel;

namespace ScrollingTerminalWindow
{
    /// <summary>
    /// example code retreived from this page
    /// http://stackoverflow.com/questions/16743804/implementing-a-log-viewer-with-wpf
    /// </summary>
    public partial class TerminalWindow : UserControl
    {
            private int index;
            private string TestData = "Lorem ipsum dolor sit amet, consectetur     adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum";
            private List<string> words;
            private int maxword;

            public ObservableCollection<LogEntry> LogEntries { get; set; }

            public TerminalWindow()
            {
                InitializeComponent();
                index = 0;
                DataContext= LogEntries = new ObservableCollection<LogEntry>();

                random = new Random();
                words = TestData.Split(' ').ToList();
                maxword = words.Count - 1;
                AddEntry();
                this.btnAddEntry.BringIntoView();
                this.btnAddEntry.Focus();

            }



             public void AddEntry()
            {
                Dispatcher.BeginInvoke((Action)(() =>     LogEntries.Add(GetRandomEntry())));
            }
             private System.Threading.Timer Timer;
             private System.Random random;
             private LogEntry GetRandomEntry()
             {
             if (random.Next(1, 10) > 1)
             {
                 return new LogEntry()
                 {
                     Index = index++,
                     DateTime = DateTime.Now,
                     Message = string.Join(" ", Enumerable.Range(5, random.Next(10, 50))
                                                          .Select(x => words[random.Next(0, maxword)])),
                 };
             }

             return new CollapsibleLogEntry()
             {
                 Index = index++,
                 DateTime = DateTime.Now,
                 Message = string.Join(" ", Enumerable.Range(5, random.Next(10, 50))
                                              .Select(x => words[random.Next(0, maxword)])),
                 Contents = Enumerable.Range(5, random.Next(5, 10))
                                      .Select(i => GetRandomEntry())
                                      .ToList()
             };

         }

         private void btnAddEntry_Click(object sender, RoutedEventArgs e)
         {
             AddEntry();
         }



    }
    public class LogEntry : PropertyChangedBase
    {
        public DateTime DateTime { get; set; }

        public int Index { get; set; }

        public string Message { get; set; }
    }

    public class CollapsibleLogEntry : LogEntry
    {
        public List<LogEntry> Contents { get; set; }
    }
    public class PropertyChangedBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            Application.Current.Dispatcher.BeginInvoke((Action)(() =>
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
            }));
        }
    }

}

TerminalWindow.XAML

<UserControl x:Class="ScrollingTerminalWindow.TerminalWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:ScrollingTerminalWindow"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
    <Style TargetType="ItemsControl" x:Key="LogViewerStyle">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <ScrollViewer CanContentScroll="True">
                        <ItemsPresenter/>
                    </ScrollViewer>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel IsItemsHost="True"/>
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <DataTemplate DataType="{x:Type local:LogEntry}">
        <Grid IsSharedSizeScope="True">
            <Grid.ColumnDefinitions>
                <ColumnDefinition SharedSizeGroup="Index" Width="Auto"/>
                <ColumnDefinition SharedSizeGroup="Date" Width="Auto"/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding DateTime}" Grid.Column="0"
                   FontWeight="Bold" Margin="5,0,5,0"/>

            <TextBlock Text="{Binding Index}" Grid.Column="1"
                   FontWeight="Bold" Margin="0,0,2,0" />

            <TextBlock Text="{Binding Message}" Grid.Column="2"
                   TextWrapping="Wrap"/>
        </Grid>
    </DataTemplate>

    <DataTemplate DataType="{x:Type local:CollapsibleLogEntry}">
        <Grid IsSharedSizeScope="True">
            <Grid.ColumnDefinitions>
                <ColumnDefinition SharedSizeGroup="Index" Width="Auto"/>
                <ColumnDefinition SharedSizeGroup="Date" Width="Auto"/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>

            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition/>
            </Grid.RowDefinitions>

            <TextBlock Text="{Binding DateTime}" Grid.Column="0"
                   FontWeight="Bold" Margin="5,0,5,0"/>

            <TextBlock Text="{Binding Index}" Grid.Column="1"
                   FontWeight="Bold" Margin="0,0,2,0" />

            <TextBlock Text="{Binding Message}" Grid.Column="2"
                   TextWrapping="Wrap"/>

            <ToggleButton x:Name="Expander" Grid.Row="1" Grid.Column="0"
                      VerticalAlignment="Top" Content="+" HorizontalAlignment="Right"/>

            <ItemsControl ItemsSource="{Binding Contents}" Style="{StaticResource LogViewerStyle}"
                      Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2"
                      x:Name="Contents" Visibility="Collapsed"/>

        </Grid>
        <DataTemplate.Triggers>
            <Trigger SourceName="Expander" Property="IsChecked" Value="True">
                <Setter TargetName="Contents" Property="Visibility" Value="Visible"/>
                <Setter TargetName="Expander" Property="Content" Value="-"/>
            </Trigger>
        </DataTemplate.Triggers>
    </DataTemplate>

</UserControl.Resources>



<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="60"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <Button Name="btnAddEntry" Click="btnAddEntry_Click" Width="80" Height="40" HorizontalAlignment="Left" VerticalAlignment="Top" Content="Add Entry" Grid.Row="0">

    </Button>
<DockPanel Grid.Row="1">
                <TextBlock Text="{Binding Count, StringFormat='{}{0} Items'}" 
           DockPanel.Dock="Top"/>
        <ItemsControl ItemsSource="{Binding}" Style="{StaticResource LogViewerStyle}" DataContext="{Binding}">
            <ItemsControl.Template>
                        <ControlTemplate>
                            <ScrollViewer CanContentScroll="True">
                                <ItemsPresenter/>
                            </ScrollViewer>
                        </ControlTemplate>
                    </ItemsControl.Template>
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <VirtualizingStackPanel IsItemsHost="True"/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl>
            </DockPanel>

</Grid>

以下是测试控件的主窗口ap的代码

mainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 ScrollingTerminalWindow;

namespace ScrollingTextBoxTestApp
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
public partial class MainWindow : Window
{
    TerminalWindow tw;
    public MainWindow()
    {
        InitializeComponent();
        tw = new TerminalWindow();
    }

    private void btn_Click(object sender, RoutedEventArgs e)
    {
        tw.AddEntry();
    }
}

}

mainwindow.xaml

<Window x:Class="ScrollingTextBoxTestApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ScrollingTerminalWindow;assembly=ScrollingTerminalWindow"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="60"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>

    </Grid.RowDefinitions>
    <Button Name="btn" Click="btn_Click" Grid.Row="0" Content="MainPageAddEntry"></Button>
    <local:TerminalWindow Margin="10,10,0,0" Name="terminalWindow1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.Row="1"/>
</Grid>

1 个答案:

答案 0 :(得分:0)

尝试替换此行:

tw = new TerminalWindow();

这一个:

tw = terminalWindow1;

您创建了另一个TerminalWindow对象,而不是您在XAML中定义的对象。您需要引用在XAML中定义的那个,然后调用其AddEntry()来查看结果。