Показать результат на экране в каждом цикле FOR? - PullRequest
1 голос
/ 14 сентября 2011

Я кодирую генератор случайных мест для самолета и использую в нем цикл FOR.Дело в том, что занятые места показывают только тогда, когда все сделано.Я хотел бы, чтобы в каждой итерации отображалось выбранное случайное место.Как можно это сделать?

Вот код, который я использую.Самолет рассчитан на 118 посадочных мест, и у меня для каждого из них есть коробка с именем «img_Seat_X».Я знаю, что есть лучший путь к этому, но об этом я мог подумать в скором времени.Заранее спасибо!

private void btn_WeightBalance_Populate_Click(object sender, EventArgs e)
{
                int passengers = Convert.ToInt32(txt_WeightBalance_Passengers.Text);
                List<int> seats = new List<int> { }; numberofSeats = 119;

                if (rdb_WeightBalance_190.Checked == true)
                    numberofSeats = 107;

                for (int x = 0; x < Passengers; x++)
                {
                    int randomNumber = RandomNumber(1, numberofSeats);

                    if (seats.Contains(randomNumber))
                        x--;

                    else
                    {

                        seats.Add(randomNumber);

                        Control[] seat = this.panWeightBalance.Controls.Find("img_Seat_" + randomNumber, true);
                        seat[0].Visible = true;
                        seat[0].Refresh();
                    }
                }
}

Разобрался!Простой Refresh () в каждой итерации сделал свое дело!Я также заменил цикл while на оператор if.

Ответы [ 5 ]

2 голосов
/ 14 сентября 2011

Во-первых, требуется чтение: Цикл сообщений Windows

@ rice указал на мою очевидную ошибку, извините за то, что вы пошли по неверному пути, спасибо rice.В любом случае вы можете выполнить эту работу в отдельном потоке и опубликовать обновления в области интерфейса пользователя с помощью класса BackgroundWorker .Вот простой пример, который обновляет метку на форме 100 раз в ответ на нажатие кнопки:

public partial class Form1 : Form
{
    BackgroundWorker _worker;
    public Form1()
    {
        InitializeComponent();
        _worker = new BackgroundWorker();
        _worker.WorkerReportsProgress = true;
        _worker.DoWork += _worker_DoWork;
        _worker.ProgressChanged += _worker_ProgressChanged;
    }

    private void _worker_ProgressChanged( object sender, ProgressChangedEventArgs e )
    {
        label1.Text = e.UserState.ToString();
    }

    private void _worker_DoWork( object sender, DoWorkEventArgs e )
    {
        for( int i = 0; i < 100; ++i )
        {
            _worker.ReportProgress( i, i );
            // allow some time between each update,
            // for demonstration purposes only.
            System.Threading.Thread.Sleep( 15 );
        }
    }   

    private void button1_Click( object sender, EventArgs e )
    {
        _worker.RunWorkerAsync();
    }
}
1 голос
/ 14 сентября 2011

По сути, вам нужно порождать фоновый поток, чтобы выполнить обработку, а затем использовать BeginInvoke для обновления элементов пользовательского интерфейса каждый раз.В этом решении вам нужно будет решить некоторые проблемы.Теперь пользователь может продолжать нажимать на кнопку, и он создаст дополнительные фоновые потоки.Наиболее распространенный механизм - это всплывающее диалоговое окно прогресса (я ненавижу модальные диалоговые окна, поэтому не делайте этого) или предотвращение повторного выполнения пользователем действия, отключив кнопку до завершения работы.* Есть дополнительные вопросы, которые необходимо решить.Например, предположение, что Control всегда будет существовать при вызове FindControl и не обрабатывать искаженный числовой текст в txt_WeightBalance_Passengers.

Обновление с «милым» ответом

    private void btn_WeightBalance_Populate_Click(object sender, EventArgs e)
    {
        var passengers = Convert.ToInt32(txt_WeightBalance_Passengers.Text);
        numberofSeats = rdb_WeightBalance_190.Checked ? 107 : 119;
        var worker = new BackgroundWorker();
        worker.DoWork += delegate
        {
            var random = new Random();
            foreach (var seatNumber in Enumerable.Range(1, Int32.MaxValue).Select(r => random.Next(numberofSeats)).Distinct())
            {
                var randomSeat = seatNumber;
                BeginInvoke((Action)(() =>
                {
                    var seat = this.Controls.Find("img_Seat_" + randomSeat, true);
                    seat[0].Visible = true;
                }));                    
                if (--passengers <= 0) break;
            }
        };
        worker.RunWorkerAsync();
    }
0 голосов
/ 14 сентября 2011

Код, который вы пишете, выбирает только случайные места максимум из 119 мест. Даже если вы используете старое оборудование, оно должно быть невероятно быстрым для запуска, поэтому я не понимаю, почему вам нужно показывать каждое место как оно распределено. Мне кажется, что вы должны разделить код. рассчитайте распределение мест и затем отобразите их любым удобным для вас способом.

Вот код для случайного выбора мест:

var passengers = Convert.ToInt32(txt_WeightBalance_Passengers.Text);
var numberofSeats = rdb_WeightBalance_190.Checked ? 107 : 119;

// Creates an array from 0 .. numberofSeats - 1
var seats = Enumerable.Range(0, numberofSeats).ToArray();

//Shuffle the first "passengers" elements of the array
for (var i = 0; i < passengers; i++)
{
    var j = RandomNumber(0, numberofSeats);
    var x = seats[i];
    seats[i] = seats[j];
    seats[j] = x;
}

//Find the first "passengers" count of seat controls
var controls = (
        from i in seats.Take(passengers)
        let c = this.Controls.Find("img_Seat_" + i, true).FirstOrDefault()
        where c != null
        select c
    ).ToArray();

Теперь, чтобы установить элементы управления сиденьем как видимые, просто сделайте это:

foreach (var c in controls)
{
    c.Visible = true;
}

Если вам нужно выполнить это в фоновом режиме и обновить пользовательский интерфейс, как это можно сделать, вы можете сделать это:

var t = new System.Threading.Thread(new ThreadStart(() =>
{
    foreach (var c in controls)
    {
        this.Invoke(new Action(() => c.Visible = true));
        // Thread.Sleep(100); // Slow it down if you wish...
    }
}));
t.Start();

Это работает для вас?

0 голосов
/ 14 сентября 2011

Дело в том, что занятые места показываются только тогда, когда все сделано.

Что ожидается, глядя на цикл while внутри цикла for:

while (Seats.Contains(randomNumber))
{
    randomNumber = RandomNumber(1, numberofSeats);
}
Seats.Add(randomNumber); 

Вы, вероятно, забыли поместить метод Add в свой цикл while.Также проверьте условие выхода - я думаю, что вы хотите выйти из цикла while, когда Contains возвращает true.

0 голосов
/ 14 сентября 2011

Вместо того, чтобы получить случайное число, проверить, не занято ли оно, и затем присвоить его, я бы взял список 1 thru numberOfSeats, перетасовал его и начал назначать места в этом порядке случайного перемешивания.Таким образом можно избежать порочного круга while (Seats.Contains(randomNumber)){...}.

...