在公共场所调用函数N次MainWindow()

时间:2016-03-26 05:12:39

标签: c# wpf xaml

[https://drive.google.com/file/d/0B1xZLc69ZnLkWWRuaE9ycmhIXzg/view?usp=sharing] 这是整个项目 - vs2013。

1您可以看到FindVisualChildren()如何将每个字母分配给按钮的内容,我需要对文件中的每个字都执行此操作,但它只能使用一次。

enter image description here

我有一个文本文件,有10个单词(每行一个)。读完单词后,将其放入文本框中,逐字母展开,以便与一些随机字母一起分配给按钮内容以填充所有按钮。此步骤使用FindVisualChildren()方法完成。

public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj)
    where T : DependencyObject
{
    if (depObj != null)
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
            if (child != null && child is T)
            {
                yield return (T)child;
            }

            foreach (T childOfChild in FindVisualChildren<T>(child))
            {
                yield return childOfChild;
            }
        }
    }
}

//Add random letters to all buttons
foreach (Button tb in FindVisualChildren<Button>(panel))
{
    tb.Content = resultsChar[array[iconta]];  
    tb.Click += Button_Click;
    ++iconta;
}

一旦分配了所有字母,用户必须使用每个按钮中的每个字母创建单词,当单词组织为对应于文本框中的单词时,则从文本中调用另一个单词,并且字母必须用其他随机字母重新分配给按钮。

一切都很好,但这是第一次。之后,我无法再调用FindVisualChildren()方法n次。这个东西只适用于第一个单词,如果我将它放在while循环中,只需向我显示最后一个单词。不是一步一步的。

1 个答案:

答案 0 :(得分:1)

如果没有可靠地再现您的问题的好Minimal, Complete, and Verifiable example,就无法知道究竟是什么问题。从您的问题描述中,听起来您可能正在构造函数中运行一些代码,而这些代码应放在其他地方,以便它可以安全地运行多次。

尽管如此,我确实同意评论的基本动机(尽管不是演示文稿),这些评论解释了你根本不应该直接搞乱视觉树。

在许多API和WPF中,做事的“正确方法”是创建一个自定义类 - 您的“视图模型 - 这是一种在完全独立的情况下维护程序状态的类型从程序的可视方面独立的方式。在你的代码示例中,这个类将跟踪要显示的单词和字母,以及程序底层逻辑的任何其他状态,以及任何控制方法或修改该状态。

作为一个例子,我写了一个可以作为你的程序中的视图模型的类:

class Model : INotifyPropertyChanged
{
    private static readonly Random _random = new Random();

    private const int _kcolumnCount = 6;
    private const int _krowCount = 4;

    private string _word;

    public ObservableCollection<char> Letters { get; private set; }

    public string Word
    {
        get { return _word; }
        set { _UpdateValue(ref _word, value); }
    }

    public int ColumnCount { get { return _kcolumnCount; } }
    public int RowCount { get { return _krowCount; } }

    public Model()
    {
        Letters = new ObservableCollection<char>();

        for (int i = 0; i < ColumnCount * RowCount; i++)
        {
            Letters.Add(' ');
        }
    }

    public void UpdateLetters()
    {
        char[] characters = new char[ColumnCount * RowCount];

        for (int i = 0; i < characters.Length; i++)
        {
            if (Word != null && i < Word.Length)
            {
                characters[i] = Word[i];
            }
            else
            {
                characters[i] = (char)('a' + _random.Next(26));
            }
        }

        for (int i = characters.Length - 1; i > 0 ; i--)
        {
            int j = _random.Next(i + 1);

            if (i != j)
            {
                char chT = characters[i];

                characters[i] = characters[j];
                characters[j] = chT;
            }
        }

        for (int i = 0; i < characters.Length; i++)
        {
            Letters[i] = characters[i];
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void _UpdateValue<T>(ref T field, T newValue, [CallerMemberName] string propertyName = null)
    {
        if (!object.Equals(field, newValue))
        {
            field = newValue;

            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

它有三个主要特征:

  1. 它存储当前的单词。
  2. 它存储要显示的当前字母列表。
  3. 它提供了一种方法,可以根据当前单词更新字母列表。
  4. 它还包括网格的行数和列数的值。

    您会注意到这个类完全可以理解为您的程序的基本逻辑,但它中没有任何与UI的实现直接相关的内容。

    编写完这样的类后,可以很容易地为用户界面创建一个简单的XAML标记:

    <Window x:Class="TestSO36231872RandomLetters.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:l="clr-namespace:TestSO36231872RandomLetters"
            xmlns:s="clr-namespace:System;assembly=mscorlib"
            Title="MainWindow" Height="350" Width="525">
    
      <Window.DataContext>
        <l:Model/>
      </Window.DataContext>
    
      <StackPanel>
        <StackPanel Orientation="Horizontal" Margin="3">
          <TextBox Width="80" Text="{Binding Word}"/>
          <Button HorizontalAlignment="Left" Content="Update Word"
                  Margin="3,0" Click="Button_Click"/>
        </StackPanel>
        <ItemsControl ItemsSource="{Binding Letters}">
          <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
              <UniformGrid IsItemsHost="True" Rows="{Binding RowCount}" Columns="{Binding ColumnCount}"/>
            </ItemsPanelTemplate>
          </ItemsControl.ItemsPanel>
          <ItemsControl.ItemTemplate>
            <DataTemplate DataType="{x:Type s:Char}">
              <Button Content="{Binding}" FontSize="16"/>
            </DataTemplate>
          </ItemsControl.ItemTemplate>
        </ItemsControl>
      </StackPanel>
    </Window>
    

    唯一剩下的就是Click事件处理程序(还有其他方法来处理用户输入,但这是最简单的,并且很适合这个特定的例子)。这是Window类的代码隐藏(即“MainWindow.xaml.cs”):

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Model model = (Model)DataContext;
    
        model.UpdateLetters();
    }
    

    这会导致在单击“更新Word”按钮的情况下调用UpdateLetters()方法。

    当然,这不是你的完整计划。我并不完全明白你的意思“用户必须使用每个按钮中的每个字母创建单词”。如果您希望用户单击网格中的按钮,则需要在模板中为按钮连接另一个处理程序,当然还要以某种方式处理上下文。但这是一个“整体'更圆的球'蜡'。我希望上面的内容足以让你指出正确的方向来处理WPF。