Форум программистов, компьютерный форум, киберфорум
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.82/74: Рейтинг темы: голосов - 74, средняя оценка - 4.82
96 / 76 / 25
Регистрация: 18.02.2016
Сообщений: 771

MVVM postgres

17.06.2020, 10:41. Показов 18709. Ответов 200
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
учу mvvm
появилось много вопросов
я создал модель
Кликните здесь для просмотра всего текста

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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
public  class GlavTables:INotifyPropertyChanged
    {
        public int id { get; set; }
        private DateTime _dateCreating;
        private string _dateTara;
        private string _dateBrutto;
        private string _dateRegistration;
        private double _tara;
        private double _brutto;
        private double _netto;
        private string _typeScales;
        private string _transportNumber;
        private string _driver;
        private string _trailer;
        private string _post;
        private string _product;
        private string _sender;
        private string _payer;
        private string _consignee;
        private string _user;
        private bool _chakRegistration;
        private bool _chakBlok;
        
        public  DateTime dateCreating
        {
            get { return _dateCreating; }
            set
            {
                if (_dateCreating == value)
                    return;
 
                _dateCreating = value;
                OnPropertyChanget("dateCreating");
 
            }
        }
        public string dateTara
        {
            get {return _dateTara; }
            set
            {
                if (_dateTara == value)
                    return;
 
                _dateTara = value;
                OnPropertyChanget("dateTara");
 
            }
        }
        public string dateBrutto
        {
            get { return _dateBrutto; }
            set
            {
                if (_dateBrutto == value)
                    return;
 
                _dateBrutto = value;
                OnPropertyChanget("dateBrutto");
 
            }
        }
        public string dateRegistration
        {
            get { return _dateRegistration; }
            set
            {
                if (_dateRegistration == value)
                    return;
 
                _dateRegistration = value;
                OnPropertyChanget("dateRegistration");
 
            }
        }
        public double tara
        {
            get { return _tara; }
            set
            {
                if (_tara == value)
                    return;
 
                _tara = value;
                OnPropertyChanget("tara");
 
            }
        }
        public double brutto
        {
            get { return _brutto; }
            set
            {
                if (_brutto == value)
                    return;
 
                _brutto = value;
                OnPropertyChanget("brutto");
 
            }
        }
        public double netto
        {
            get { return _netto; }
            set
            {
                if (_netto == value)
                    return;
 
                _netto = value;
                OnPropertyChanget("netto");
 
            }
        }
        public string typeScales
        {
            get { return _typeScales; }
            set
            {
                if (_typeScales == value)
                    return;
 
                _typeScales = value;
                OnPropertyChanget("typeScales");
 
            }
        }
        public string transportNumber
        {
            get { return _transportNumber; }
            set
            {
                if (_transportNumber == value)
                    return;
 
                _transportNumber = value;
                OnPropertyChanget("transportNumber");
 
            }
        }
        public string driver
        {
            get { return _driver; }
            set
            {
                if (_driver == value)
                    return;
 
                _driver = value;
                OnPropertyChanget("driver");
 
            }
        }
        public string trailer
        {
            get { return _trailer; }
            set
            {
                if (_trailer == value)
                    return;
 
                _trailer = value;
                OnPropertyChanget("trailer");
 
            }
        }
        public string post
        {
            get { return _post; }
            set
            {
                if (_post == value)
                    return;
 
                _post = value;
                OnPropertyChanget("post");
 
            }
        }
        public string product
        {
            get { return _product; }
            set
            {
                if (_product == value)
                    return;
 
                _product = value;
                OnPropertyChanget("product");
 
            }
        }
        public string sender
        {
            get { return _sender; }
            set
            {
                if (_sender == value)
                    return;
 
                _sender = value;
                OnPropertyChanget("sender");
 
            }
        }
        public string payer
        {
            get { return _payer; }
            set
            {
                if (_payer == value)
                    return;
 
                _payer = value;
                OnPropertyChanget("payer");
 
            }
        }
        public string consignee
        {
            get { return _consignee; }
            set
            {
                if (_consignee == value)
                    return;
 
                _consignee = value;
                OnPropertyChanget("consignee");
 
            }
        }
        public string user
        {
            get { return _user; }
            set
            {
                if (_user == value)
                    return;
 
                _user = value;
                OnPropertyChanget("user");
 
            }
        }
        public bool chakRegistration
        {
            get { return _chakRegistration; }
            set
            {
                if (_chakRegistration == value)
                    return;
 
                _chakRegistration = value;
                OnPropertyChanget("chakRegistration");
 
            }
        }
        public bool chakBlok
        {
            get { return _chakBlok; }
            set
            {
                if (_chakBlok == value)
                    return;
 
                _chakBlok = value;
                OnPropertyChanget("chakBlok");
 
            }
        }
 
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanget(string propertyName="")
        {
           
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

создал сервис , который должен заполнять данными я это сделал так
Кликните здесь для просмотра всего текста

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
 public BindingList<GlavTables> LoadData()
        {
            try
            {
                string conn = "Server=192.168.1.111;Port=5432;User Id=postgres;Password=123;Database=postgres111";
                DataSet ds = new DataSet();
                DataTable dt = new DataTable();
                string sql = " SELECT * FROM \"glav\" ";
                NpgsqlConnection ConnLocal = new NpgsqlConnection(conn);
                NpgsqlDataAdapter da = new NpgsqlDataAdapter(sql, ConnLocal);
                da.Fill(ds);
                BindingList<GlavTables> glavTavles = new BindingList<GlavTables>();
                for (int i=0; ds.Tables[0].Rows.Count > i;i++)
                {
                    glavTavles.Add(new GlavTables
                {
                    
                    id = Convert.ToInt32(ds.Tables[0].Rows[i][0].ToString()),
                    dateCreating = Convert.ToDateTime(ds.Tables[0].Rows[i][2].ToString()),
                    dateTara = ds.Tables[0].Rows[i][3].ToString(),
                    dateBrutto = ds.Tables[0].Rows[i][4].ToString(),
                    dateRegistration = ds.Tables[0].Rows[i][5].ToString(),
                    tara = nullNo(ds.Tables[0].Rows[i][6].ToString()),
                    brutto = nullNo(ds.Tables[0].Rows[i][7].ToString()),
                    netto = nullNo(ds.Tables[0].Rows[i][8].ToString()),
                    typeScales = ds.Tables[0].Rows[i][11].ToString(),
                    transportNumber = ds.Tables[0].Rows[i][12].ToString(),
                    driver = ds.Tables[0].Rows[i][13].ToString(),
                    trailer = ds.Tables[0].Rows[i][14].ToString(),
                    post = "Пост1",
                    product = ds.Tables[0].Rows[i][16].ToString(),
                    sender = ds.Tables[0].Rows[i][17].ToString(),
                    payer = ds.Tables[0].Rows[i][18].ToString(),
                    consignee = ds.Tables[0].Rows[i][19].ToString(),
                    user = ds.Tables[0].Rows[i][20].ToString(),
                    chakRegistration = true,
                    chakBlok = false
                
                });
                }
                return glavTavles;
            }
            catch
            {  return null; }
        }

после чего в основном классе
Кликните здесь для просмотра всего текста

C#
1
2
3
 GlavTablesIOServices glavTablesIOServices = new GlavTablesIOServices();
            _glavTables = glavTablesIOServices.LoadData();
            dg_glavGrid.ItemsSource = _glavTables;

и тут первый вопрос. можно это сделать без циклов ? например сразу конвертировать в BindingList и как вообще правильно заполнять данными из бд?

дальше я показываю таблицу в view
Кликните здесь для просмотра всего текста

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
 <DataGrid 
 
                x:Name="dg_glavGrid" AutoGenerateColumns="False" >
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding Path=id}" IsReadOnly="True" Header="№"/>
                    <DataGridTextColumn Binding="{Binding Path=dateCreating}" IsReadOnly="True" Header="Дата создания"/>
                    <DataGridTextColumn Binding="{Binding Path=dateTara}" IsReadOnly="True" Header="Дата тара"/>
                    <DataGridTextColumn Binding="{Binding Path=dateBrutto}" IsReadOnly="True" Header="Дата брутто"/>
                    <DataGridTextColumn Binding="{Binding Path=dateRegistration}" IsReadOnly="True" Header="Дата оформления"/>
                    <DataGridTextColumn Binding="{Binding Path=tara}" IsReadOnly="True" Header="Тара"/>
                    <DataGridTextColumn Binding="{Binding Path=brutto}" IsReadOnly="True" Header="Брутто"/>
                    <DataGridTextColumn Binding="{Binding Path=netto}" IsReadOnly="True" Header="Нетто"/>
                    <DataGridTextColumn Binding="{Binding Path=typeScales}" IsReadOnly="True" Header="Тип весов"/>
                    <DataGridTextColumn Binding="{Binding Path=transportNumber}" IsReadOnly="True" Header="Т/С"/>
                    <DataGridTextColumn Binding="{Binding Path=driver}" IsReadOnly="True" Header="Водитель"/>
                    <DataGridTextColumn Binding="{Binding Path=trailer}" IsReadOnly="True" Header="Прицеп"/>
                    <DataGridTextColumn Binding="{Binding Path=post}" IsReadOnly="True" Header="Имя поста"/>
                    <DataGridTextColumn Binding="{Binding Path=product}" IsReadOnly="True" Header="Товар"/>
                    <DataGridTextColumn Binding="{Binding Path=sender}" IsReadOnly="True" Header="Отправитель"/>
                    <DataGridTextColumn Binding="{Binding Path=payer}" IsReadOnly="True" Header="Плательщик"/>
                    <DataGridTextColumn Binding="{Binding Path=consignee}" IsReadOnly="True" Header="Получатель"/>
                    <DataGridTextColumn Binding="{Binding Path=user}" IsReadOnly="True" Header="Пользователь"/>
                    <DataGridCheckBoxColumn Binding="{Binding Path=chakRegistration, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="True" Header="Оформление"/>
                    <DataGridCheckBoxColumn Binding="{Binding Path=chakBlok, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="True" Header="Доступность"/>
                </DataGrid.Columns>
            </DataGrid>
 
        </Grid>
 
    </Grid>

и снова вопрос. мне нужно добавлять данные в BindingList и при событии добавления/удаления/изменения делать изменения в бд? Или просто делать запросы в бд update/insert и после этого заново заполнять данными? второе звучит проще и логичней для меня.
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
17.06.2020, 10:41
Ответы с готовыми решениями:

Mvvm
Форумчане помогите разобраться есть простенькая модель public partial class Category:ViewModelBase { private int...

x:Name в MVVM
Добрый день, как обращаться к объектам из VM по их x:Name? Например, у меня есть канвас в который я докидываю картинки по нажатию...

MVVM
Здравствуйте, я в среде WPF нахожусь очень мало, посмотрел книжки, решил читать Мэтью Макдональда, стоит ли мне сразу изучать MVVM или...

200
96 / 76 / 25
Регистрация: 18.02.2016
Сообщений: 771
08.04.2021, 14:26  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Элд Хасп Посмотреть сообщение
при вставки ролика YouTube надо указывать только его Id
понятно. а то думаю почему не работает
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
08.04.2021, 14:27
Цитата Сообщение от onimor Посмотреть сообщение
Но пролаг видно.
лагает
Не могу врубиться про какой лаг вы пишите.
Мне кажется работает абсолютно одинаково.
0
96 / 76 / 25
Регистрация: 18.02.2016
Сообщений: 771
08.04.2021, 14:32  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Мне кажется работает абсолютно одинаково.
в первом видео после нажатия войти, провисает слегка. видно же хорошо

Добавлено через 1 минуту
диалог не исчезает даже до конца. зависает и пропадает

Добавлено через 35 секунд
А во втором видео он уже плавно исчезает
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
08.04.2021, 19:24
Цитата Сообщение от onimor Посмотреть сообщение
диалог не исчезает даже до конца. зависает и пропадает
Разглядел.
Покажу вам другой навигатор - без VM.
Но чуть позже.
1
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
08.04.2021, 19:24
onimor, добавил фиксацию:
Добавлено Решение с примером реализации UI навигатора.
Контролы-страницы навигатора создаются однократно.
Обновите локальный Репозиторий и откройте в нём Решение PostsUINavigatorSln.
1
09.04.2021, 07:55

Не по теме:

Тупо десять страниц продуктивной дискуссии, а не срача. Мне кажется, что уже после пятой, ведущему нужно начинать начислять деньги за углублённую консультацию...

0
96 / 76 / 25
Регистрация: 18.02.2016
Сообщений: 771
09.04.2021, 09:41  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Обновите локальный Репозиторий и откройте в нём Решение PostsUINavigatorSln.
Спасибо!

Не понял как работает
C#
1
contentUC.Content = Resources["signinUC"];
он ведь пустой.

Добавлено через 6 минут
Цитата Сообщение от Usaga Посмотреть сообщение
Тупо десять страниц продуктивной дискуссии, а не срача. Мне кажется, что уже после пятой, ведущему нужно начинать начислять деньги за углублённую консультацию...
Не передать словами как я благодарен Элд Хасп. Мне уже кажется, что меня скоро пошлют лесом с такой кучей вопросов.
Боюсь узнать сколько стоят такие консультации.. Но я не против поддержать данатом, хоть и не большим(
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
09.04.2021, 09:49
Забыл, что что Репозиторий не публичный.
Для посетителей Форума выкладываю архив Решения с примером UI навигатора: PostsUINavigatorSln.7z

Краткие объяснения:

1) Есть три независимые VM.
В ресурсах App создаётся Локатор в каждом свойстве которого экземпляр VM:
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<Application x:Class="PostsUINavigator.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:PostsUINavigator"
             xmlns:vm="clr-namespace:ViewModels;assembly=ViewModels"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <local:Locator x:Key="locator">
            <local:Locator.PostsViewModel>
                <vm:PostsViewModel/>
            </local:Locator.PostsViewModel>
            <local:Locator.SettingsViewModel>
                <vm:SettingsViewModel/>
            </local:Locator.SettingsViewModel>
            <local:Locator.SigninViewModel>
                <vm:SigninViewModel/>
            </local:Locator.SigninViewModel>
        </local:Locator>
    </Application.Resources>
</Application>
2) Для двух VM SettingsViewModel и SigninViewModel используются Представления (UserControl) получающие Контекст Данных из свойства Локатора.
Пример Представления SettingsViewModel. Для удобства Конструирования (Разработки) так же задаётся Контекст Данных Времени Разработки:
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
<UserControl x:Class="PostsUINavigator.SettingsUC"
             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:PostsUINavigator"
             xmlns:vm="clr-namespace:ViewModels;assembly=ViewModels"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800"
             d:DataContext="{DynamicResource settingsVmDD}"
             Background="LightSkyBlue"
             DataContext="{Binding SettingsViewModel, Source={StaticResource locator}}">
    <UserControl.Resources>
        <vm:SettingsViewModel x:Key="settingsVmDD"
                            Top="123456"
                            Left="789"/>
    </UserControl.Resources>
    <UniformGrid Columns="2">
        <TextBlock Text="Сверху:"/>
        <TextBlock Text="{Binding Top}" />
        <TextBlock Text="Слева:"/>
        <TextBlock Text="{Binding Left}"/>
    </UniformGrid>
</UserControl>
3) Для Представления Поста Контекст Данных получается из выделенного поста в PostsViewModel.
XML
13
             DataContext="{Binding PostsViewModel.SelectedPost, Source={StaticResource locator}}">
4) Панель управления Навигатора состоит из двух частей.
В нижней части кнопки для показа Представлений SettingsUC и SigninUC.
В верхней части ItemsControl с кнопками для каждого поста.
Справа от панели управления Регион для показа нужного Представления.
В нём объявлен ContentPresenter - задавая в его свойстве Content нужное Представление обеспечивается их смена.

В ресурсах Окна объявлено по экземпляру каждого представления.
Во всех кнопках панели управления используются кликеры.
В кликерах из ресурсов Окна получается нужный экземпляр Представления и записывается в ContentPresenter.Content.
Для кнопок постов также добавлена логика по получению поста из Контекста Данных кнопки и записи его в свойство locator.PostsViewModel.SelectedPost.

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

Конвертер:
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
using System;
using System.Globalization;
using System.Linq;
using System.Windows.Data;
 
namespace Common.Converters
{
    public class AnyEqualsConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (values == null || values.Length < 2)
                return false;
            return values.Skip(1).Any(v => Equals(values[0], v));
        }
 
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
 
        public static AnyEqualsConverter Instance { get; } = new AnyEqualsConverter();
    }
}
Окно:
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
44
45
46
47
48
49
50
51
52
53
54
<Window x:Class="PostsUINavigator.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:PostsUINavigator" xmlns:converters="clr-namespace:Common.Converters;assembly=Common"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <local:PostUC x:Key="postUC"/>
        <local:SigninUC x:Key="signinUC"/>
        <local:SettingsUC x:Key="settingsUC"/>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition Width="5*"/>
        </Grid.ColumnDefinitions>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <ItemsControl ItemsSource="{Binding PostsViewModel.Posts, Source={StaticResource locator}}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Button Content="{Binding Title}" Click="SelectedPost">
                            <Button.Style>
                                <Style TargetType="Button">
                                    <Style.Triggers>
                                        <DataTrigger Value="True">
                                            <DataTrigger.Binding>
                                                <MultiBinding Converter="{x:Static converters:AnyEqualsConverter.Instance}">
                                                    <Binding/>
                                                    <Binding Path="PostsViewModel.SelectedPost" Source="{StaticResource locator}"/>
                                                </MultiBinding>
                                            </DataTrigger.Binding>
                                            <Setter Property="Background" Value="#00FF00"/>
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </Button.Style>
                        </Button>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
            <StackPanel Grid.Row="1">
                <Button Content="Новый вход" Click="SigninClick"/>
                <Button Content="Настройки" Click="SettingsClick"/>
            </StackPanel>
        </Grid>
        <ContentPresenter x:Name="contentUC" Grid.Column="1"/>
    </Grid>
</Window>
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
using System.Windows;
using ViewModels;
 
namespace PostsUINavigator
{
    /// <summary>
    /// Логика взаимодействия для MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        private void SigninClick(object sender, RoutedEventArgs e)
        {
            contentUC.Content = Resources["signinUC"];
        }
 
        private void SettingsClick(object sender, RoutedEventArgs e)
        {
            contentUC.Content = Resources["settingsUC"];
        }
 
        private void SelectedPost(object sender, RoutedEventArgs e)
        {
            contentUC.Content = Resources["postUC"];
            Locator locator = (Locator)FindResource("locator");
            locator.PostsViewModel.SelectedPost = (PostDataVM) ((FrameworkElement)sender).DataContext;
        }
    }
}
3
96 / 76 / 25
Регистрация: 18.02.2016
Сообщений: 771
09.04.2021, 10:06  [ТС]
Цитата Сообщение от onimor Посмотреть сообщение
Не понял как работает
Не увидел, что ресурсы были в view, не там искать начал.. тогда понятно.
Надеюсь сегодня успею проверить как будет работать.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
09.04.2021, 10:10
5) "Долгие" методы требуют несколько иной реализации.
Потенциально они могут вызвать лаги GUI.
Поэтому их необходимо выполнять асинхронно.
В Примере это продемонстрированно с методом подгрузки данных для выбранного поста.
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
using Simplified;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
 
namespace ViewModels
{
    public class PostsViewModel : BaseInpc
    {
 
        public ObservableCollection<PostDataVM> Posts { get; }
        = new ObservableCollection<PostDataVM>()
        {
            new PostDataVM() {Id="FL48", Title="Первый пост"},
            new PostDataVM() {Id="WO73", Title="Третий пост"}
        };
 
        private PostDataVM _selectedPost;
        public PostDataVM SelectedPost { get => _selectedPost; set => Set(ref _selectedPost, value); }
 
        // Прогрузка данных для выбранного поста
        private async void LoadPostDataAsync()
        {
            await Task.Run(() =>
            {
                // Код обновления свойств PostsViewModel и SelectedPost данными для выбранного поста.
            });
        }
 
        protected override void OnPropertyChanged(string propertyName, object oldValue, object newValue)
        {
            base.OnPropertyChanged(propertyName, oldValue, newValue);
 
            if (propertyName == nameof(SelectedPost))
                LoadPostDataAsync();
        }
    }
}
При смене выделенного поста автоматически вызывается асинхронный метод LoadPostDataAsync, в котором и обновляются все нужные данные.
Так как метод асинхронный, то не задерживает поток в котором происходило присвоение нового значения свойству SelectedPost.
1
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,775
09.04.2021, 10:14
А при таком способе инстанциации VM можно как-то обеспечить инжект зависимостей через конструктор VM? Там ведь, обычно, требуются и экземпляры разных частей Модели, и логгер.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
09.04.2021, 10:20
Цитата Сообщение от Usaga Посмотреть сообщение
Тупо десять страниц продуктивной дискуссии, а не срача.
Даже скучно...?


ТС хочет научиться.
А срач возникает там, где знаний мало, а амбиций много.
И вместо изучения чел доказывает "Один я д'Артаньян ....".

Добавлено через 1 минуту
Цитата Сообщение от kotelok Посмотреть сообщение
А при таком способе инстанциации VM можно как-то обеспечить инжект зависимостей через конструктор VM? Там ведь, обычно, требуются и экземпляры разных частей Модели, и логгер.
Конечно.
Я же просто для упрощения примера показал инициализацию локатора в XAML.
Его можно инициализировать и в CB App, как вы и делали.

Добавлено через 3 минуты
Суть примера несколько в другом.
То что Представления не создаются каждый раз заново по шаблону.
А создаются один раз при первом обращении к ним в ресурсах.
В последующем используются уже созданные экземпляры.

Побочным эффектом этого будет сохранение Представлением состояния UI элементов в нём.
Если при использовании шаблона для этого требуется привязка каждого нужного состояния к свойству Контекста Данных, то здесь это происходит автоматически, так как экземпляр Представления будет существовать пока его явно не уничтожат.
1
96 / 76 / 25
Регистрация: 18.02.2016
Сообщений: 771
09.04.2021, 12:15  [ТС]
Элд Хасп, теперь пролаг только в первый раз при создании, потом все плавно. Чтоб менять UC из vm нужно делать отдельный словарь с UC и его юзать в vm? Просто есть некоторые методы , который нужно выполнить до и после смены uc.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
09.04.2021, 12:27
Цитата Сообщение от onimor Посмотреть сообщение
Чтоб менять UC из vm нужно делать отдельный словарь с UC и его юзать в vm?
Нет.
В VM не должно быть никаких UI элементов.
Мне, кажется, вы, вообще, напрасно вытянули логику Навигатора в VM.
В данном случае, навигатор никак не взаимодействует с данными и следовательно ему нечего делать в VM.

Добавлено через 2 минуты
Цитата Сообщение от onimor Посмотреть сообщение
Просто есть некоторые методы , который нужно выполнить до и после смены uc.
Вызывайте их в кликерах.

По своему функционалу VM независима от Представления.
Он не знает и не должна знать какое Представление сейчас для неё используется или, вообще, есть это Представление или нет.
Если Представлению в своей логике надо вызвать какие-то методы VM, то Представление это должно делать само.

Добавлено через 4 минуты
onimor, UI навигатор на кликерах - это только пример.
Можно так же задать команды, Контекст Данных Окну и т.д.
То есть сделать максимально близко к типичному для ViewModel способу.

НО!!!
Не каждый Контекст Данных - это обязательно ViewModel.
ViewModel - это слой из паттерна MVVM связывающий Представление с Данными.
При этом в Представлении может быть использован очень похожий тип, но который не имеет отношения к Данным.
Допустим, функция Навигатора - это переключение страниц.
И если это переключение не связанно с Данными, то это полностью функционал Представления никак не связанный с VM.
1
96 / 76 / 25
Регистрация: 18.02.2016
Сообщений: 771
09.04.2021, 12:30  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Вызывайте их в кликерах.
То есть теперь метод входа из vm будет вызывать не команда, а просто кликер? и если проверка usera прошла, то
C#
1
CP.Content = Resources["weightWindowUC"];
?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
09.04.2021, 12:40
Цитата Сообщение от onimor Посмотреть сообщение
То есть теперь метод входа из vm будет вызывать не команда, а просто кликер? и если проверка usera прошла, то
Вы за авторизацию (в моём примере SighinVM) ?

Можно сделать так:
1) В VM событие SigningClosed, которое создаётся при успешной авторизации или при отказе от неё.
2) В кликере происходит подписка на это событие;
3) Панель управления переводится в состояние IsEnabled=false;
4) Показывается SigninUC;
5) Выход из кликера.

В обработчике OnSigningClosed:
1) Происходит отписка от SigningClosed;
2) Включается панель управления IsEnabled=true;
3) Показывается PostUC;
4) Если надо - изменяется выбранный пост;
5) Выход из обработчика.
1
96 / 76 / 25
Регистрация: 18.02.2016
Сообщений: 771
09.04.2021, 13:09  [ТС]
Элд Хасп, вспомнились WF). Тогда к этому еще добавиться 2 события и пару методов.

Потому что пока model не завершит все опросы, операции в других потоках и прочее- будет висеть диалог на подобие загрузки и параметры не откроются.
После параметров нужно подождать пока все обратно запуститься и только потом показать PostUC.

Это нормально что будет столько CB?

Добавлено через 12 минут
Если так подумать то пролаг и пролаг. SQL SMS вообще не отвечает пока ищет сервера и нормально им
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
09.04.2021, 15:08
Цитата Сообщение от onimor Посмотреть сообщение
Это нормально что будет столько CB?
Можно и в CB сделать, но как я писал - в моём примере так для упрощения.
Если логики многовато, то всё же я бы перенёс её в отдельный класс и реализовал через команды.

Добавлено через 16 минут
Цитата Сообщение от onimor Посмотреть сообщение
Если так подумать то пролаг и пролаг. SQL SMS вообще не отвечает пока ищет сервера и нормально им
Это, конечно, не принципиально, а скорее изучение различных подходов к реализации.

Что плохо в вашем текущем Решении MainWindowsVM:
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using WSAMP.Infrastructure.Commands.Base;
using WSAMP.Infrastructure.Dialog;
using WSAMP.Models.CurrentData;
using WSAMP.Models.MainWindow;
using WSAMP.Models.Setting;
using WSAMP.ViewModels.Base;
 
namespace WSAMP.ViewModels
{
    public class MainWindowsVM : ViewModelBase
    {
 
 
        #region SwitchingUserControls
 
        private object _currentVM;
        ///<summary>отображаемая VM</summary>
        public object CurrentVM
        {
            get => _currentVM;
            set => Set(ref _currentVM, value);
        }
 
        #endregion
 
        #region Вход
        private string _entryUserLogin;
        public string EntryUserLogin
        {
            get => _entryUserLogin;
            set => Set(ref _entryUserLogin, value);
        }
 
        private string _entryUserPassword;
        public string EntryUserPassword
        {
            get => _entryUserPassword;
            set => Set(ref _entryUserPassword, value);
        }
 
        private bool _entryRemember;
        public bool EntryRemember
        {
            get => _entryRemember;
            set => Set(ref _entryRemember, value);
        }
 
        private bool _entryVisibleDialog;
        public bool EntryVisibleDialog
        {
            get => _entryVisibleDialog;
            set => Set(ref _entryVisibleDialog, value);
        }
        #endregion
 
        #region Посты
        private ObservableCollection<PostDto> _collectionOfPosts= new();
 
        ///<summary>UC  настроек</summary>
        public ObservableCollection<PostDto> CollectionOfPosts
        {
            get => _collectionOfPosts;
            set => Set(ref _collectionOfPosts, value);
        }
 
        private PostDto _selectedPosts = new();
 
        ///<summary>Выбраный пост</summary>
        public PostDto SelectedPosts
        {
            get => _selectedPosts;
            set
            {
                Set(ref _selectedPosts, value);
                //отображаем текущий пост
                CurPost = SelectedPosts==null? "-":SelectedPosts.PostName;
                ToggleButtonStatus = false;
            }
        }
       
        #endregion
 
        #region Верхняя панель
        private string _curUser="-";
        ///<summary>Текущий пользователь</summary>
        public string CurUser
        {
            get => _curUser;
            set => Set(ref _curUser, value);
        }
 
        private string _curPost="-";
        ///<summary>Текущий пост</summary>
        public string CurPost
        {
            get => _curPost;
            set => Set(ref _curPost, value);
        }
 
        private bool _toggleButtonStatus;
        ///<summary>Состояние кнопки</summary>
        public bool ToggleButtonStatus
        {
            get => _toggleButtonStatus;
            set => Set(ref _toggleButtonStatus, value);
        }
 
        #endregion
 
        #region выдвижная панель слева
 
 
        #endregion
 
        private bool _privilege = false;
        ///<summary>Текущий пользователь</summary>
        public bool Privilege
        {
            get => _privilege;
            set => Set(ref _privilege, value);
        }
 
        /// <summary>Модель с настройками </summary>
        private readonly SettingModel settingModel;
        private readonly MainWindowsModel mainWindowsModel;
        private CurrentUser currentUser;
        private readonly WeightWindwosVM weightWindwosVM;
        ParametersVM parametersVM;
        public MainWindowsVM(CurrentUser currentUser,
                             SettingModel settingModel,
                             MainWindowsModel mainWindowsModel,
                             WeightWindwosVM weightWindwosVM,
                             ParametersVM parametersVM)
        {
            this.parametersVM = parametersVM;
            this.currentUser = currentUser;
            this.mainWindowsModel = mainWindowsModel;
            this.settingModel = settingModel;
            this.weightWindwosVM = weightWindwosVM;
 
            StaticBinding.StaticVisbl = false;
 
            EntryUserLogin=Properties.User.Default.Login;
            EntryUserPassword =Properties.User.Default.Password;
            EntryRemember=Properties.User.Default.RememberUser;
        }
 
        public MainWindowsVM()
        {
            if (!DesignerProperties.GetIsInDesignMode(new DependencyObject()))
                throw new Exception("Конструктор по умолчанию только для Времени Разработки!");
        }
 
        /// <summary>Получаем все настройки, запускаем основные компоненты программы, отображаем главное окно с нужными UC </summary>
        ///Получеам тут так как нужно ждать инициализации DialogHost + нужна строка коннекта для входа
        private async void Initialization()
        {
            try
            {
                //показываем диалог загрузки
                Dialogs.ProgressBox("Загрузка");
 
                ////ПОКА ТУТ ЧТОБ БЫЛА ОШИБКА ВЫЗЫВАЕТСЯ
              
                //получаем настройки для коннекта к postgres
                //если вернулось true то пытаемся авторизоваться и подгружаем остальные настроки текущего поьзователя
                if (await settingModel.GetSetting())
                {
                    //автоматичекий вход если чекер запомнить был активен
                    AutoEntry();
                }
               
            }
            catch (Exception ex)
            {
                Dialogs.MessageBox($"{ex.Message}");
                //показываем диалог для входа в программу
                EntryVisibleDialog = true;
            }
 
        }
 
        /// <summary>
        /// все закрываем и показываем диалог входа в программу
        /// </summary>
        private async void ChangeUser()
        {
            //закрываем боковое меню
            ToggleButtonStatus = false;
 
            Dialogs.ProgressBox("Загрузка");
            await mainWindowsModel.UserOffAsync();
            //показываем диалог входа
            
           
            CurrentVM = null;
            StaticBinding.StaticVisbl = false;
            Dialogs.Close();
            EntryVisibleDialog = true;
        }
 
        /// <summary>
        /// автоматичекий вход
        /// </summary>
        private void AutoEntry()
        {
            if (EntryRemember)
            {
               Entry();
            }
            else
            {
                Dialogs.Close();
                EntryVisibleDialog = true;
 
            }
        }
 
        /// <summary>
        /// вход в программу + загрузка настроек для текущего пользователя
        /// </summary>
        private async void Entry()
        {
            try
            {
                //скрываем диалог авторизации
                EntryVisibleDialog = false;
                Dialogs.ProgressBox("Загрузка");
 
                if (/*await mainWindowsModel.UserVerification(EntryUserLogin, EntryUserPassword)*/true)
                {
                    //при успешном входе сохраняем параметры. если чекер "запомнить" не активен то пароль не запоминаем
                    Properties.User.Default.Login = EntryUserLogin;
                    Properties.User.Default.Password = EntryUserPassword = EntryRemember ? EntryUserPassword : "";
                    Properties.User.Default.RememberUser = EntryRemember;
                    Properties.User.Default.Save();
 
                    //отображаем текущего пользователя
                    //CurUser = currentUser.Login Временно;
                    CurUser = EntryUserLogin;
                    //Privilege = currentUser.Rights == "Admin" Временно;
                    Privilege = true;
                   
                    CollectionOfPosts.Clear();
                    //получаем все посты для текущего пользователя
                    //foreach (var Post in await mainWindowsModel.GetPostsForTheUserAsync()) временно
                    await Task.Run(()=>Thread.Sleep(200));
                    List<PostDto> Posts = null ;
                    await Task.Run(() =>
                    {
                        Posts = new List<PostDto>
            {
              new PostDto {Id=1,PostName="Пост №1",User="admin"},
              new PostDto {Id=2,PostName="Пост №3",User="tes2"},
              new PostDto {Id=3,PostName="Главный выезд",User="tes1"}
            };
                       
                    });
 
 
                    foreach (var Post in Posts)
                        CollectionOfPosts.Add(Post);
 
                    if (CollectionOfPosts.Count!= 0)
                    {
                        //Выбираем первый пост из списка
                        SelectedPosts = CollectionOfPosts.FirstOrDefault();
 
                        ////Получаем все настройки для текущего поста
                        //await mainWindowsModel.GetTheSettingsOfTheCurrentPost(SelectedPosts.Id);
 
 
                        //tcp , modbus, камеры и прочее
 
 
 
 
                        //показываем основной UC   
                        CurrentVM = weightWindwosVM;
 
                        //активируем панель сверху
                        StaticBinding.StaticVisbl = true;
 
                        //закрываем диалог загрузки
                        Dialogs.Close();
                    }
                    else
                    {
                        throw new Exception($"Для пользователя '{currentUser.Login}' нет доступных постов!"); 
                    }
 
                     
                }
            }
            catch (Exception ex)
            {
                Dialogs.MessageBox(ex.Message);
                EntryVisibleDialog = true;
            }
           
        }
 
        private void GoParameters()
        {
            CurrentVM = parametersVM;
            ToggleButtonStatus = false;
        }
 
        #region Command
        private ICommand _goParametersCommand;
        public ICommand GoParametersCommand => _goParametersCommand ??= new RelayCommand(GoParameters);
 
        private ICommand _entryCommand;
        public ICommand EntryCommand => _entryCommand ??= new RelayCommand(Entry, CanEntryCommand);
        private bool CanEntryCommand()
        {
            if (EntryUserLogin!="" && EntryUserLogin !=string.Empty && EntryUserPassword != "" && EntryUserPassword != string.Empty)
                return true;
 
            return false;
        }
 
        private ICommand _changeUserCommand;
        public ICommand ChangeUserCommand => _changeUserCommand ??= new RelayCommand(ChangeUser);
 
        private ICommand _dialogHostLoaded;
        public ICommand DialogHostLoaded => _dialogHostLoaded ??= new RelayCommand(Initialization);
 
        private ICommand _exitCommand;
        public ICommand ExitCommand => _exitCommand ??= new RelayCommand(App.Current.Shutdown);
        #endregion
    }
}
Эта ViewModel слишком большая и многофункциональная.
Главная её функция - это обеспечить работу Навигатора.
И по сути это часть Представления, а не ViewModel.
Так же как и Локатор: в нём есть свойства для привязки, реализация INPC - но это не ViewModel.

Вот и вам надо разделить MainWindowsVM на два класса: Навигатор и, собственно, главная VM.
При этом если вы используете концепцию с главной VM, то вам вам вряд ли нужен Локатор.
Вместо Локатора в ресурчах App создайте экземпляр Главной VM.
Локатор, по сути, и выполняет её роль, когда она явно в VM не реализована.
1
96 / 76 / 25
Регистрация: 18.02.2016
Сообщений: 771
09.04.2021, 16:08  [ТС]
Элд Хасп, хорошо. Попробую разделить тогда, чтоб навигация была отдельно.
0
96 / 76 / 25
Регистрация: 18.02.2016
Сообщений: 771
28.06.2021, 16:53  [ТС]
Элд Хасп, Очень извинюсь не мог этим заняться.

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Главная её функция - это обеспечить работу Навигатора.
Из навигатора там переключение между постами и 1 UC "параметры".
Получается просто переношу свойства и методы, которые что-то с ними делают в отдельный класс? А как тогда привязать сразу 2 класса в датаконтекст? или в контекст панелей просто нужно?

И еще 1 вопрос если можно. Сейчас в UC Поста vm одна на все посты. При переключении меняется только id внутри и данные под этот id приходят. Может лучше при переключении создавать новую vm каждый раз?

Прежде чем что-то делать дальше, хотелось бы привести все в нормальный вид. Вы как гуру wpf могли бы помочь указать на ошибки и подтолкнуть на путь для решения?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
28.06.2021, 16:53

MVVM
Добрый день! Пытаюсь написать программу в стиле MVVM. Вопрос такой: как передать SelectedItem TreeView из xaml с помощью Binding в...

Model в MVVM
Доброго времени суток. Начал изучать MVVM и даже что-то получается сделать, но не могу сообразить, что должно быть в Model? Программа...

Mvvm datagrid ef
Здравствуйте форумчане, у меня такая проблема есть приложение При выделении datagrid биндю Selecteditem в textboxы мои ...

WPF MVVM
Привет всем! Изучаю патерн MVVM. Не могу понять как реализовать ее, если допустим мне необходимо одно и тоже окно использовать для разных ...

MVVM патерн
Всем привет. Уже писал по поводу данного стиля программирования, более менее разобрался, но некоторые вещи не понятны. Допустим у меня...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
200
Ответ Создать тему
Новые блоги и статьи
Запустил конкурс "тем и промптов для текстовых квестов созданных почти чисто ИИ"
Adler 06.10.2026
Всем привет! За последние три-четыре дня я создал более 16 текстовых квестовых игр используя преимущественно по одному запросу к ИИ на игру. Мне так понравилось смотреть все ветки/ сцены во всех. . .
ИИ не может найти нужный язык в списке
Supersumestria 05.10.2026
Я ему даю вот такое изображение и прошу найти и подчеркнуть немецкий язык. Возвращает он вот это: https:/ / i. **********/ vqBWLe2. png Нужную строчку в 3й колонке просто выдумал. . Это. . .
Новая последняя моя музыка в SUNO
zorxor 05.10.2026
Здравствуйте, дорогие мои друзья! С большой радостью я хотел бы представить вам свою новую последнею музыку, которую сгенерировала мне по моей просьбе нейросеть SUNO. С уважением, zorxor. Это. . .
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru