powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / ProgressBar в отдельном окне
25 сообщений из 42, страница 1 из 2
ProgressBar в отдельном окне
    #39589714
Qwe.Qwe1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Наверняка гуру это делали лет дцать назад, может быть вспомните и подскажите как реализовать такое (WPF, придерживаясь MVVM): есть у меня N кнопок в основном окне, для каждой есть команда во ViewModel, в которой выполняется длительная операция:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
private ICommand _сalcCommand1;
public ICommand CalcCommand1
{
    get { return _сalcCommand1 ?? (_сalcCommand1 = new CommandHandler(param => Calculate1(param), _canExecute)); }
}
public void Calculate1(object obj)
{
    // TODO: отобразить окошко с прогрессом

    // Запуск длительной операции
    ModelObject.Calculate1();

    // или цикл, чтобы уведомлять прогрессбар о продвижении значения
}



Мне нужно по нажатию на кнопку перед запуском этих операций вывести отдельное окно и там вывести ProgressBar с итерациями.
Я сталкивался раньше на WinForms с тем, что там ГУИ было в том же окне. Так же читал, что тот же BackgroundWorker вроде как уже устарел и для WPF можно реализовать задуманное проще. А даже если и не устарел, то как его прикрутить для другого окна?
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39589734
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Qwe.Qwe1,
Алтернативы интересны?
Прогресс в панели задач винды.
Пару строк
Код: c#
1.
TaskBar.SetProgressValue(i, count)
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39589791
Qwe.Qwe1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Скорее это интересно в дополнение, но все равно спасибо)
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39589812
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Qwe.Qwe1,
Диалоговые и т.д. окна не делаются по MVVM imho.
Значит, все как обычно.
Отдельное окно и события туда сюда на делегатах (как вариант).
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39589817
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Qwe.Qwe1,
И в wpf и в winforms вы можете делать либо в отдельном, либо в том же. Это чисто дизайн.
По потокам, в 4.5 появился async
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39589830
Qwe.Qwe1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ну я создал окно "WaitWindow" и в XAML-разметке обозначил Прогресс-бар, текст "Ждите.." и т.д. Для этого окошка я могу не использовать MVVM, ладно уж..) Теперь надо как-то его отобразить и управлять потоком и прогресс-баром без велосипеда)
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39589853
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Petro123Qwe.Qwe1,
Диалоговые и т.д. окна не делаются по MVVM imho.
Значит, все как обычно.
Отдельное окно и события туда сюда на делегатах (как вариант).
Окна очень даже прекрасно делаются по MVVM - инжектируются в модель как сервис.
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39589857
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры Павловныинжектируютсяесли без DI то интересно глянуть
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39589859
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Qwe.Qwe1,
Вы потоки сначала сделайте. Они же ниже view
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39589866
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Это только пример, а не код для продакшена, много чего нет, так как всё написано с нуля на коленке.
Класс WindowManager является промежуточным, между View и ViewModel и лучше его размещать в отдельной сборке, если сборки View и ViewModel разнесены.
Пример сделан, примерно так, как я люблю реализовывать работу с окнами, по этому не пинайте сильно.

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
using System;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;

namespace WpfApp3
{
    /// <summary>
    /// Данный класс является промежуточным между модель и представлением
    /// Он позволяет открывать окна из модели представления на основе основе типа модели представления
    /// На основе типа модели окна находится соотвествующий стиль окна в ресурса приложения.
    /// То есть для окна должен быть предопределен стиль хранящийся в ресурсах приложения или главного окна
    /// </summary>
    public static class WindowManager
    {
        /// <summary>
        /// Открываем диалоговое окно
        /// </summary>
        /// <param name="model"></param>
        public static void ShowDialog(BaseWindowModel model)
        {
            var app = Application.Current;
            //Ищем стиль в ресурсах приложения
            var style = (Style)app.TryFindResource(model.GetType());
            //Если не нашли ищем в главном окне
            if (style == null)
            {
                style = (Style)app.MainWindow.TryFindResource(model.GetType());
            }
            
            //можно много где еще поискать, но если не нашли, то кидаем исключение
            if (style == null)
            {
                throw new Exception("Can't show window, style not found");
            }

            //создаем окно, задаем контекст, стиль
            var window = new Window
            {
                Style = style,
                DataContext = model
            };

            //Для нормальной реализации менеджера окна нужно больше чем примерчик, 
            //по этому пока оставляю вот так, безобразно, за то работает
            model.CloseWinow += (s,e) => window.Close();
            //открываем диалог
            window.ShowDialog();
        }
    }

    /// <summary>
    /// Класс реализующий ICommand, часто имеет название RelayCommand, это его упращенная версия
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ActionCommand<T> : ICommand
    {

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
        public bool LongRunning { set; get; }
        public ActionCommand(Action<T> action, Func<T, bool> condition)
        {
            Action = action;
            Condition = condition;
        }
        public ActionCommand(Action<T> action)
        {
            Action = action;
        }

        public Action<T> Action { set; get; }
        public Func<T, bool> Condition { set; get; }


        public bool CanExecute(object parameter)
        {
            return Condition == null || Condition((T)parameter);
        }

        public void Execute(object parameter)
        {
            Action?.Invoke((T)parameter);
        }
    }


    /// <summary>
    /// Базовая модель представления окна
    /// </summary>
    public abstract class BaseWindowModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public event EventHandler CloseWinow;

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        /// <summary>
        /// Метод закрывет окно связанное с данной моделью
        /// </summary>
        protected void CloseWindow()
        {
            CloseWinow?.Invoke(this, null);
        }
    }

    /// <summary> Модель представления главного окна, в данном примере создается прямо из View </summary>
    public class MainModel : BaseWindowModel
    {
        private ActionCommand<object> _myCommand;
        public ActionCommand<object> MyCommand => _myCommand ?? (_myCommand = new ActionCommand<object>(OnMyCommand));

        private void OnMyCommand(object obj)
        {
            //Создаем объект который будет отвечать за обновления прогресса выполнеия в 
            //STA потоке
            var progress = new Progress<double>();
            //Создаем источник ключа для отмены операции
            var tokenSource = new CancellationTokenSource();
            var token = tokenSource.Token;
            //Создаем модель представления для отображения прогресса выполнения
            var progressModel = new ProgressModel(progress, tokenSource);
            //Запускаем асинхронную операцию в отдельном потоке через Task
            var task = Task.Run(() => LongOperation(progress, token), token);
            //Открываем окно
            WindowManager.ShowDialog(progressModel);
        }

        /// <summary>
        /// Метод реализующий длительную операцию с возможностью отмены и отчетом выполнения 
        /// </summary>
        /// <param name="progress"></param>
        /// <param name="token"></param>
        private void LongOperation(IProgress<double> progress, CancellationToken token)
        {
            for(var i = 0; i < 100; i++)
            {
                if (token.IsCancellationRequested) break;
                progress.Report((double)i);
                Task.Delay(200).Wait();
            }
        }
    }

    /// <summary> Модель окна с прогресс баром. </summary>
    public class ProgressModel : BaseWindowModel
    {


        private readonly IProgress<double> _progress;
        private readonly CancellationTokenSource _tokenSource;

        public ProgressModel(Progress<double> progress, CancellationTokenSource tokenSource)
        {
            _progress = progress;
            progress.ProgressChanged += OnProgressChanged;
            _tokenSource = tokenSource;
        }

        private double _progressValue;
        /// <summary>
        /// Значение прогресса выполнения от 0 до 100
        /// </summary>
        public double ProgressValue
        {
            set
            {
                _progressValue = value;
                OnPropertyChanged(nameof(ProgressValue));
            }
            get
            {
                return _progressValue;
            }
        }

        private ActionCommand<object> _cancel;
        /// <summary> Команда отмены операции </summary>
        public ActionCommand<object> Cancel => _cancel ?? (_cancel = new ActionCommand<object>(OnCancel));

        private void OnCancel(object obj)
        {
            _tokenSource.Cancel();
            CloseWindow();
        }

        /// <summary>
        /// Обрабочик события изменения прогресса выполнения
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnProgressChanged(object sender, double e)
        {
            ProgressValue = e;
        }

    }
}


Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
<Window x:Class="WpfApp3.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp3"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MainModel/>
    </Window.DataContext>
    <Window.Resources>
        <DataTemplate x:Key="ProgressModelTemplate" DataType="{x:Type local:ProgressModel}">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <ProgressBar Grid.Row="0" Margin="4" Width="300" Height="50" 
                             Value="{Binding ProgressValue}" 
                             Minimum="0" Maximum="100"/>
                <StackPanel Grid.Row="1"
                            Orientation="Horizontal">
                    <Button Command="{Binding Cancel}" Margin="4" Padding="10,5"
                            Content="Cancel"/>
                </StackPanel>
            </Grid>
        </DataTemplate>

        <Style x:Key="{x:Type local:ProgressModel}" TargetType="{x:Type Window}">
            <Setter Property="SizeToContent" Value="WidthAndHeight"/>
            <Setter Property="Content" Value="{Binding DataContext, RelativeSource={RelativeSource Self}}"/>
            <Setter Property="ContentTemplate" Value="{StaticResource ProgressModelTemplate}"/>
        </Style>

    </Window.Resources>
    <Grid>
        <Button HorizontalAlignment="Center" VerticalAlignment="Center"
                Width="200" Height="80"
                Content="Run"
                Command="{Binding MyCommand}"/>
    </Grid>
</Window>
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39589868
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ну и забыл сказать, я всё упаковал в 2 файла, ни какого другого кода в примере нет
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39589892
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtes,
Менеджер для всех это круто.
Аффтар!
У вас выбор, одна, 10 или 300 строк.
Дерзайте.
Удачи!
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39590005
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Petro123Сон Веры Павловныинжектируютсяесли без DI то интересно глянуть
Если что, инжект сервиса можно делать без использования DI-фреймворков и паттернов а-ля service locator - собственно, суть DI заключается не в использовании фреймворков, а в развязке зависимостей через интерфейсы. Ваш К.О.
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39590014
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры Павловны,
Ну я просто не видел такой вариант. Везде что видел это инжектируемые поля в классе и конфиг с временем жизни.
Я пока ручками и ни сколько не критикую.
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39590044
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
service locator это анти-паттерн по сути и он может сильно запутывать, особенно если есть несколько реализаций одного сервиса
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39590100
Qwe.Qwe1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Roman Mejtes, как всегда круто) Буду пробовать пойти предложенным путем. А можно таки упростить все и обойтись без "public static class WindowManager"? Прямо окно с прогресс-баром заточить на свой шаблон и прочее, без такой вот универсальности?
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39590130
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Qwe.Qwe1Roman Mejtes, как всегда круто) Буду пробовать пойти предложенным путем. А можно таки упростить все и обойтись без "public static class WindowManager"? Прямо окно с прогресс-баром заточить на свой шаблон и прочее, без такой вот универсальности?это типа: а можно mvvm, но без буквочек vv?
))
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39590131
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
конечно можно, можно и через Content делать окно, а потом просто открыть его из модели. Это несколько нарушает правила шаблона о том, что модель представления не знает о самом представлении, но можно и не следовать этому правилу.
В 1 из проектов поверх WindowManager у меня еще был LayoutManager который отвечал за работу вкладок (табов) в окнах, возможность перекидывания вкладок из окна в окно, и т.д.
Так же WM отвечал за MessageBox'ы из VM, за возможность открытия, закрытия окон, за проброс маршрутизируемых команд из диалоговых окон в вызывающие, следил из иерархией окон, предоставлял всякие другие механизмы взаимодействия между окнами, при этом выше упомянутое правило соблюдается.
Ведь создавай модель и вызывая команду на открытия окна для этой модели я не указываю ни каких типов из View, они будет разрешаться автоматически на основе имеющихся стилей.
Есть куча примеров как взаимодействовать с окнами из VM, гуглите, это просто тот вариант, который использую я, не знаю, есть ли аналогичные в интернете
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39590134
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Qwe.Qwe1,
Получается вам нужно начать с делегата.
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39590139
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtesможно и через Content делать окно, а потом просто открыть его из модели.вот этот наверно.... пару фраз буквально.
Интересно.
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39590165
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Petro123,

каких фраз?
Окно наследует элемент управления ContentControl.
У ContentControl'а есть свойств Content.
Свойство хитрое тем, что в зависимости от содержимого оно будет обрабатываться по разному

Eсли мы задаем этому свойству в качестве значения объект унаследованный от UIElement (другой элемент управления), то оно будет отображать его как своё содержимое.
Такой подход использует в стандартном варианте.
Когда вы создаете окно, его свойством по умолчанию является свойство Content.
Код: xml
1.
2.
3.
<Window>
    <Grid/>
</Window>


равносильно:
Код: c#
1.
var window = new Window() { Content = new Grid() }


Но если в Content передать объект наследованный не от UIElement, то для его визуализации будет использовать шаблон данных заданный в свойстве ContentTemplate или полученный из ContentTemplateSelector'а
В примере выше, окно ProgressBar'а использует 2ой метод, а главное окно 1ый.
У обоих есть свои плюсы и минусы, а иногда стоит их комбинировать, что недостатков не было :)
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39590189
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtesкаких фраз?развить вашу мысль в пару фраз имел ввиду.
Т.к. контекст понимаю для биндинга. Для прогрессбара не понимаю imho.
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39590196
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Petro123,

Context!=Content
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39590260
Qwe.Qwe1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А как в LongOperation, помимо итерации прогресса, можно передать произвольный текст в диалоговое окно, который бы отображался рядом с прогрессбаром: "Идет операция i" и т.п.
...
Рейтинг: 0 / 0
ProgressBar в отдельном окне
    #39590279
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Qwe.Qwe1А как в LongOperation, помимо итерации прогресса, можно передать произвольный текст в диалоговое окно, который бы отображался рядом с прогрессбаром: "Идет операция i" и т.п.
использовать в generic типа не double, а пользовательский класс
Progress<double> -> Progress<FooClass>
...
Рейтинг: 0 / 0
25 сообщений из 42, страница 1 из 2
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / ProgressBar в отдельном окне
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]