Гость
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / ProgressBar в отдельном окне / 25 сообщений из 42, страница 1 из 2
24.01.2018, 10:03
    #39589714
Qwe.Qwe1
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Наверняка гуру это делали лет дцать назад, может быть вспомните и подскажите как реализовать такое (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
24.01.2018, 10:25
    #39589734
Petro123
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Qwe.Qwe1,
Алтернативы интересны?
Прогресс в панели задач винды.
Пару строк
Код: c#
1.
TaskBar.SetProgressValue(i, count)
...
Рейтинг: 0 / 0
24.01.2018, 11:10
    #39589791
Qwe.Qwe1
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Скорее это интересно в дополнение, но все равно спасибо)
...
Рейтинг: 0 / 0
24.01.2018, 11:28
    #39589812
Petro123
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Qwe.Qwe1,
Диалоговые и т.д. окна не делаются по MVVM imho.
Значит, все как обычно.
Отдельное окно и события туда сюда на делегатах (как вариант).
...
Рейтинг: 0 / 0
24.01.2018, 11:34
    #39589817
Petro123
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Qwe.Qwe1,
И в wpf и в winforms вы можете делать либо в отдельном, либо в том же. Это чисто дизайн.
По потокам, в 4.5 появился async
...
Рейтинг: 0 / 0
24.01.2018, 11:39
    #39589830
Qwe.Qwe1
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Ну я создал окно "WaitWindow" и в XAML-разметке обозначил Прогресс-бар, текст "Ждите.." и т.д. Для этого окошка я могу не использовать MVVM, ладно уж..) Теперь надо как-то его отобразить и управлять потоком и прогресс-баром без велосипеда)
...
Рейтинг: 0 / 0
24.01.2018, 11:55
    #39589853
Сон Веры Павловны
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Petro123Qwe.Qwe1,
Диалоговые и т.д. окна не делаются по MVVM imho.
Значит, все как обычно.
Отдельное окно и события туда сюда на делегатах (как вариант).
Окна очень даже прекрасно делаются по MVVM - инжектируются в модель как сервис.
...
Рейтинг: 0 / 0
24.01.2018, 12:00
    #39589857
Petro123
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Сон Веры Павловныинжектируютсяесли без DI то интересно глянуть
...
Рейтинг: 0 / 0
24.01.2018, 12:02
    #39589859
Petro123
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Qwe.Qwe1,
Вы потоки сначала сделайте. Они же ниже view
...
Рейтинг: 0 / 0
24.01.2018, 12:10
    #39589866
Roman Mejtes
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Это только пример, а не код для продакшена, много чего нет, так как всё написано с нуля на коленке.
Класс 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
24.01.2018, 12:11
    #39589868
Roman Mejtes
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
ну и забыл сказать, я всё упаковал в 2 файла, ни какого другого кода в примере нет
...
Рейтинг: 0 / 0
24.01.2018, 12:21
    #39589892
Petro123
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Roman Mejtes,
Менеджер для всех это круто.
Аффтар!
У вас выбор, одна, 10 или 300 строк.
Дерзайте.
Удачи!
...
Рейтинг: 0 / 0
24.01.2018, 13:31
    #39590005
Сон Веры Павловны
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Petro123Сон Веры Павловныинжектируютсяесли без DI то интересно глянуть
Если что, инжект сервиса можно делать без использования DI-фреймворков и паттернов а-ля service locator - собственно, суть DI заключается не в использовании фреймворков, а в развязке зависимостей через интерфейсы. Ваш К.О.
...
Рейтинг: 0 / 0
24.01.2018, 13:36
    #39590014
Petro123
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Сон Веры Павловны,
Ну я просто не видел такой вариант. Везде что видел это инжектируемые поля в классе и конфиг с временем жизни.
Я пока ручками и ни сколько не критикую.
...
Рейтинг: 0 / 0
24.01.2018, 13:57
    #39590044
Roman Mejtes
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
service locator это анти-паттерн по сути и он может сильно запутывать, особенно если есть несколько реализаций одного сервиса
...
Рейтинг: 0 / 0
24.01.2018, 14:43
    #39590100
Qwe.Qwe1
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Roman Mejtes, как всегда круто) Буду пробовать пойти предложенным путем. А можно таки упростить все и обойтись без "public static class WindowManager"? Прямо окно с прогресс-баром заточить на свой шаблон и прочее, без такой вот универсальности?
...
Рейтинг: 0 / 0
24.01.2018, 15:08
    #39590130
Petro123
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Qwe.Qwe1Roman Mejtes, как всегда круто) Буду пробовать пойти предложенным путем. А можно таки упростить все и обойтись без "public static class WindowManager"? Прямо окно с прогресс-баром заточить на свой шаблон и прочее, без такой вот универсальности?это типа: а можно mvvm, но без буквочек vv?
))
...
Рейтинг: 0 / 0
24.01.2018, 15:08
    #39590131
Roman Mejtes
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
конечно можно, можно и через Content делать окно, а потом просто открыть его из модели. Это несколько нарушает правила шаблона о том, что модель представления не знает о самом представлении, но можно и не следовать этому правилу.
В 1 из проектов поверх WindowManager у меня еще был LayoutManager который отвечал за работу вкладок (табов) в окнах, возможность перекидывания вкладок из окна в окно, и т.д.
Так же WM отвечал за MessageBox'ы из VM, за возможность открытия, закрытия окон, за проброс маршрутизируемых команд из диалоговых окон в вызывающие, следил из иерархией окон, предоставлял всякие другие механизмы взаимодействия между окнами, при этом выше упомянутое правило соблюдается.
Ведь создавай модель и вызывая команду на открытия окна для этой модели я не указываю ни каких типов из View, они будет разрешаться автоматически на основе имеющихся стилей.
Есть куча примеров как взаимодействовать с окнами из VM, гуглите, это просто тот вариант, который использую я, не знаю, есть ли аналогичные в интернете
...
Рейтинг: 0 / 0
24.01.2018, 15:09
    #39590134
Petro123
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Qwe.Qwe1,
Получается вам нужно начать с делегата.
...
Рейтинг: 0 / 0
24.01.2018, 15:13
    #39590139
Petro123
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Roman Mejtesможно и через Content делать окно, а потом просто открыть его из модели.вот этот наверно.... пару фраз буквально.
Интересно.
...
Рейтинг: 0 / 0
24.01.2018, 15:36
    #39590165
Roman Mejtes
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
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
24.01.2018, 16:02
    #39590189
Petro123
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Roman Mejtesкаких фраз?развить вашу мысль в пару фраз имел ввиду.
Т.к. контекст понимаю для биндинга. Для прогрессбара не понимаю imho.
...
Рейтинг: 0 / 0
24.01.2018, 16:11
    #39590196
Shocker.Pro
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ProgressBar в отдельном окне
Petro123,

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


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