« first day (843 days earlier)      last day (2188 days later) » 
03:00 - 16:0016:00 - 23:00

4:03 PM
@vitidev Я как-то чистым MVVM обхожусь пока. А напомните, если можно, в чём разница?
 
@VladD ну у каждого свой взгляд. Когда возникает вопрос "а куда собственно поместить обработчик в котором будет код который дергает модель, а не служит для обслуживания вьюхи" то код попадает в одну из вьюмоделей. В частности может в рутовую. Да и хоть куда получается перемешивание вьюкода и рабочего кода, пусть его даже минимум

Пэтому этот код выносится в контроллеры. Хотя в инете у каждого свое мнение что должны делать контроллеры. Но в моем видении - все то, что относится к логике приложения, а не к отображению должно быть вынесено из вьюмоделей дабы их не перегружать
 
@vitidev А, C — это как бы бизнес-логика?
Отдельно от VM?
 
@VladD в моем понимании и в том, который можно нагуглить, да. С реализациями туго поэтому в моей реализации это набор классов контроллеров как в MVC в которых невизуальная логика и на них можно забиндиться напрямую из вьюхи и они доступны везде в пределах корневой вм и вложенных.

заодно я хотел из них слать по мессенджеру события по шине, но поскольку они "глобальные" то использую простые события там где нужно. Пока более удобного не придумал
 
@vitidev Угу, понял. Почему бы и нет в общем-то.
Получается тогда V <-> VM <-> C <-> M?
Или VM тоже «видит» M?
 
ну я не вижу смысла в излишней абстракции. стартует корневая VM. она стартует набор контроллеров. Их несколько чтобы не мешать в кучу. Они доступны из любой дочерней VM и из вьюхи. По факту VM остается та же, просто делегирует то, что не касается конкретно работы вида контролерам. Также доступен прямой биндинг из вьюхи. Поэтому у контроллера тоже есть команды ( ну пока я так решил, а можно будет сделать объект комманд для биндинга чтобы не мусорить в контроллерах и сделать там только методы)
Когду умирает корневая вьюмодель, То тащит за собой в небытие все контролеры сегмента
вот как в вебе - на фронтенде работает вид: вьюхи + вм, но если чо надо то дергается контроллер из MVC на сервере. Их там не один для удобства. Тут точно такое же
Для этого пришлось таскать owner vm везде. только ссылка у меня ровно на одну родительскую и DialogService сам раскрутит стек вьюмоделей у себя и найдет нужное родительское окно для показа диалога.
я реализовал вашу идею передавать сервисю вьюмодель и по ней вычислять окно для диалога.
 
4:18 PM
@vitidev Тогда кто кого видит?
V ведь не видит C, правильно?
А только VM
Или в C команды, которые V тоже может дёргать непосредственно?
 
V видит VM. но VM обычно god object. поэтому из VM выносится часть логики, что не касается VM в C. А потом "а почему бы не быть этим C глобальными". И далее VM дергает эти C куда был вынесен код. А потом "ну и зачем если мне надо дернуть Cиз 3х мест с безумной вложенностью мне делать 3 команды и 3 вызова C - нужно дать возможность биндиться напрямую на команды C (или делегатор команд)" - и вот мы биндимся на C там где нам не нужна косвенность
то есть C это слой как в MVC к которому может обратиться как слой VM так и V напрямую (не вижу причин не позволять этого, а удобства налицо)
 
@vitidev Хм, вот прямо даже V может обращаться к C?
Или ограниченно, только дёргать команды?
 
xaml же.
<Button
Height="30"
Command="{Binding Controller[Main].SwitchModeCommand, Mode=OneTime}"
где бы я не написал такой биндинг он будет вести всегда в одно место
 
Угу, команды — это понятно. А имеет право V сказать в code-behind ((VM)DataContext).Controller.ExecuteBusinessLogic()?
 
имеет. контроллеры для того и нужны чтобы их дергали когда нужно обратиться к логике приложения с указанием "сделай это".
подтягивать данные для отображения вид может и сам - это ж не веб в конце концов
>Угу, команды — это понятно

сложно сказать. я склоняюсь к мысли что им не место в контроллерах и что надо бы сделать узел команд, а в контроллерах оставить только методы - исключительно для чистоты и чтобы контроллеры меньше походили на вьюмодели (потому даже INPC не хочу им давать)
а с диалогами получилось так: раскручиваем цепочку Owner во вьюмоделях и смотрим нет ли кого с окном. Если нашли - тот и будет owner. Тот же механизм с немодальнымии.
@VladD А если любите задачи, то придумайте как нормально быть с немодальными окнами чтобы они были независимыми. А то открытие ShowDialog где угодно блокирует ВСЕ окна приложения.
Я сделал открытие "диалогов" через Show и нижележащее окно перехватываю Preview* и перевожу фокус на открытое "диалоговое" окно. но это же костыль. любой может перехватить Preview* в контроле и до окна оно не дойдет

также можно повесить хук типа WndProc, но дальше мысль не идет что там ловить то чтобы было как в дефолтном поведении заблокированного окна
 
4:46 PM
@VladD Я тут
 
@vitidev А почему ShowDialog, а не Show?
если оно немодальное
@Bretbas Я посмотрел, у меня всё нормально красится
Ну за исключением фокуса, это классическая проблема :)
<Menu.Resources>
    <Style TargetType="MenuItem">
        <Setter Property="HorizontalAlignment" Value="Stretch"/>
        <Setter Property="Background" Value="Blue"/>
        <Setter Property="HeaderTemplate">
            <Setter.Value>
                <DataTemplate>
                    <Border>
                        <TextBlock Text="{Binding}" HorizontalAlignment="Center"/>
                    </Border>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>
HeaderTemplate нужен, чтобы текст был по центру
 
@VladD блин, извини пожалуйста, но мне нужно опять работу небольшую сделать:( Не могу щас говорить
 
@Bretbas Давай :)
 
5:01 PM
@VladD мне нужны немодальные которые могут открывать свои дочерние модальные. А ShowDialog открытый в одном из таких немодальных окон блокирует все окна на свете
 
@vitidev Ну да, но он же так делает небось по Windows Style Guide'у?
Если нужно лезть в HWND, с хорошей долей вероятности хочется странного
Сейчас посмотрю на каком-нибудь многооконном майкрософтовском приложении
 
@VladD ну да. я хочу открыть 2 диалоговых дочерник окна по одному у 2х немодальных окон. Я не могу это сделать прямо, поэтому приходится изворачиваься
обычно просто не открывают дочерних диалогов или открывают одно
 
@vitidev Ну вот сейчас попробовал на Word'е
Модальное окно в одном окне блокирует другое
Так что это правильное поведение модальных окон.
 
я ж не говорю что оно неправильное. я хочу это ограничение обойти. для этого я открываю "диалоги" через Show и мне нужно запретить поползновения к родительским окнам
обычно любой тык на родительское окно подсвечивает диалог который все блокирует. у меня то же самое. но мой перехват тыков ненадежен ибо сделан через Preview*
 
Ну, тут я плохой помощник. Я не умею противостоять фреймворку, который пытается заставить меня сделать правильно. Я сдаюсь и делаю правильно.
И вообще, модальные диалоги — это плохо.
Меня (не как программиста, а как юзера) они жутко бесят.
 
5:10 PM
на то они и диалоги чтобы быть модальными. немодальное окно диалогом не назовут
 
@vitidev Совершенно верно. И они не нужны.
Я не хочу, чтобы программа блокировала всю работу, пока я не отвечу на очень важный (с её точки зрения) вопрос.
Пусть расположит вопрос на экране, я когда-нибудь к нему вернусь
А модальные диалоги меня раздражают.
Поэтому я стараюсь ими в своём коде не пользоваться.
 
ну это проще сказать. просто список чего либо + форма добавления. форму добавления куда если не на диалог? расположить где то на форме? там места нет. пусть выедет панелька с формой - так она перекроет собой список.
 
@vitidev Нанять дизайнера, и пусть найдёт место.
Если в окне программы нет места для чего-нибудь, там слишком много всего.
Дизайн программы не должен выглядеть так:
На экране должно быть много места, и дополнительный временный диалог должен помещаться
 
ну это уже крайность. а так обычно диалоговые окна самое оно. потому что не уродуют окно в котором данные в попытках "куда бы его разместить".

ну это далеко не всегда так. когда нужен табличный дизайн то места нет вообще
 
@vitidev Ну да. Я вот признаю только FileOpen и FileSave в качестве модальных диалогов.
Это крайность, но не нужно к ней пытаться приблизиться
А если не приближаться, то место ненадолго найдётся
Если окно уродуется при добавлении диалога поля вода, наверное, оно переполнено уже
Из всех дизайнов мне больше всего нравится дизайн страницы поиска гугла. Строка посередине, пара кнопок, много чистого места.
 
5:20 PM
в моем дизайне если уж юзер открыл диалоговое окно то ему нечего делать пока он не сделает то для чего он его открыл. собственно не будет у него задач "а двай я тыкну на чо то другое ибо я ж сам не знаю зачем открыл окно диалога в коором форма, а я ее не заполняю"
 
@vitidev Почему тогда диалоговое окно? Почему не отдельный экран приложения?
Вот прекрасный пример — окно поиска подстроки в Word'е
Раньше оно было модальным. Открыл — заполни и нажми Enter, или Esc.
Сейчас, слава богу, Майкрософт наняли дизайнера, который заставил их сделать окно немодальным
И можно заполнять когда мне хочется, а не когда программисту
 
ну окно поиска подразумевает работу под ним не закрывая его. с чего ему вдруг быть модальным мне не понять. а вот заполнение формы для элемента списка должно только может быть немодальным хотя возникает вопрос "зачем юзер открыл форму если он не собирается ее заполнять, ведь ему нечем заняться на форме пока он не закроет форму. А если есть чем - неправильная перегруженная форма"
 
@vitidev «только может быть немодальным» или «модальным»?
 
ну по идее это окно может пережить работу со списком будучи незаполненным и потому может быть немодальным без вреда для работы и без особого усложнения кода. А вот если это окно допустим есть категории в комбо и нужно прямо тут добавить еще одну категорию - тык на кнопку, откроется список категорий с возможность его редактировать - вот это окно должно быть модальным ибо может возникнуть сложностьсинхронизировать редактирование и нижележащий комбо
 
5:35 PM
@vitidev А в чём сложность, если у нас Binding и MVVM?
По поводу редактирования элемента списка, это же классический юзкейс для master/detail view
Слева список, справа редактируется текущий элемент списка
 
не классический. открываете форму допустим пользователя на много полей - выделили место. далее там есть выбор чего либо в компбо и тут вы понимаете что не хватает элементов в этом комбо. нужно добавить что то - а там кнопка рядом с комбо - прыг на нее и вот не закрыавя форму пользователя уже редактируем то что в комбо
 
Комбобокс тоже не очень удобно, особенно если элементов много. А того же Word'а есть контрол в виде двух списков: выбранные и доступные элементы. И кнопочки в центре перемещают между списками. Очень удобно, кстати.
@vitidev Ничччего не понял в этом описании.
Что значит не хватает элементов?
Мы заходим в диалог редактирования юзера, и в нём настраиваем detail view?
Ну это смешение функциональности, нужно как-то SRP к этому применить
Не должен экран уметь всё, а то у нас будет приложение как на предыдущем скриншоте
Хотите отредактировать detail view — пусть юзер нажмёт кнопку, снавигируйте в интерфейс редактирования detail view, дайте юзеру отредактировать, снавигируйте назад
Ну и лучше всего не давать юзеру редактировать detail view.
Интерфейс должен быть правильным с самого начала. Чтобы юзеру не пришлось играть в project manager'а и править интерфейс за вас
Ну или увольте PM'а, раз он у вас не работает
А то конечно, если вы открыли редактирование юзера в detail view, а в нём открыли модальный диалог редактирования самого detail view, а в нём открыли модальный поддиалог выбора средств редактирования detail view, то у вас и получается необходимость в окнах 12 уровней. Не делайте так, пожалейте мозг пользователя.
(Пойду покамест домой, зайду через полчасика где-то.)
 
5:52 PM
@VladD юзер говорит " я решил добавить пользователя и в момент добавления пользователя понял что не хватает категорий. не хочу я закрывать пользоателя чтобы куда то топать добавлять категорию. хочу добавить категорию in-place"
 
6:09 PM
@VladD все я написал. Куда скинуть код?:)
public class MenuPopupPlacementAttachedProperty : BaseAttachedProperty<MenuPopupPlacementAttachedProperty, PlacementMode>
{
	private Menu menu = null;

	public override void OnValueChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
	{
		menu = d as Menu;

		if( menu.IsLoaded )
		{
			SubscribeChildren();
		}
		else
		{
			RoutedEventHandler handler = null;
			handler = (oo, ee) =>
			{
				SubscribeChildren();
				menu.Loaded -= handler;
			};
			menu.Loaded += handler;
		}
	}
@VladD собственно, накладываем это AttachedProperty на контрол Menu, и все. Все Popup'ы будут раскрываться в ту сторону, в какую прикажешь.
@VladD без Task'ов, и всяких ожиданий открытия. Код в принципе легкий. Установка , в какую сторону должен открываться Popup происходит на лету
А как сюда изображения скидывать? Прям в чат? Кто-нибудь знает?
 
6:25 PM
@Bretbas Кнопка "upload..."
 
у меня нет ее
 
@Bretbas а так
 
как?
 
@Bretbas Сейчас должно появиться было, докинул до 100 пару голосов..
 
она только появляется, если голоса позволяют?
 
6:30 PM
@Bretbas Ходит такой слух
 
А может зажатием каких нибудь клавиш?
 
@Bretbas <tab>,<tab>,<enter>
 
ну и? Я в факе че то не нашел
 
8
Q: SO Chat No Upload Button

Philippos SlicherI was in an SO chat room with some awesome people and I noticed that I don't have the upload button, I only have send. All I have is this: And that's what another user sees:

 
100 репы нужно:)
 
6:45 PM
@vitidev Клиент всегда неправ. artlebedev.ru/kovodstvo/sections/87
Не нужно потакать идеям клиента насчёт дизайна.
Общее правило такое:
Если клиент говорит, что что-то плохо, то его следует слушать, он прав. А если он говорит, как нужно сделать, то его не нужно слушать, он не прав.
 
Всем пока! До завтра
 
@Bretbas До завтра! Я посмотрю код чуть позже
И отпишусь в чате
 
@VladD ок:)
 
Как принято в шарпе делать, если один поток что-то себе проверяет (например температуру), а потом ему нужно сообщить об аварии остальными потокам? ServiceProvider + AtomicBool?
 
@VladimirGamalyan Task + event?
Никаких низкоуровневых примитивов
 
6:49 PM
@VladD пошел читать
 
event'ы встроены в язык
а вместо потоков сейчас используют Task'и
@vitidev Дизайн должен быть не кастомизируемый, а такой, который не нужно кастомизировать. Сразу правильный. Иначе выгнать дизайнера и взять профессионально пригодного.
 
7:07 PM
@Bretbas Ага, ничего, тоже хорошо. Минус — у всех элементов одинаковое смещение.
А что такое BaseAttachedProperty?
Ещё один минус, наверное, общий для обоих решений — memory leak
Или его нет, сейчас подумаю.
Дело в том, что если какой-то пункт меню не открывался, то событие никогда не наступит, я вот думаю, насколько это в порядке.
У нас останется ссылка на элемент из MenuPopupPlacementAttachedProperty, а на него — из меню
Хотя если вся группа сдохнет, то это будет просто кольцо ссылок, и сборщик мусора его съест
Окей, вот что эта штука не поддерживает: добавление и удаление элементов меню.
Потому что у нас SubscribeChildren() пробегает только один раз
И если какой-то элемент появился позже, то он не в игре
 
7:42 PM
@VladD, а что там с моим автогридом? ;)
 
8:17 PM
@Андрей Ой, а где он? Я пропустил...
Ааааа! Вспомнил
 
8:53 PM
8 hours ago, by VladD
А ну попробую налабать, момент
 
@Андрей Ага
У меня были какие-то наброски, но они остались на работе
Сейчас пишу по новой, получше
 
Ну эт я шучу, конечно вы мне ничего не должны :)
@VladD, а у вас в Мюнхене UTC+1, вроде?
 
@Андрей Да по идее
У нас 22:00
@Андрей Ну мне и самому интересно
 
@VladD просто интересно, у вас рабочий день до 19:00 что ли?
 
@Андрей Да
Иногда до 19:30
Но и начинается в 10 / 10:30
 
9:03 PM
@VladD а чё так поздно? Или вы сами себе такой график определили?
 
@Андрей Ну это самое позднее, когда ещё можно :) Я сова
 
 
1 hour later…
10:17 PM
@Андрей Написал
    class GridEx : Grid
    {
        public static string GetLocation(DependencyObject obj) => (string)obj.GetValue(LocationProperty);
        public static void SetLocation(DependencyObject obj, string value) => obj.SetValue(LocationProperty, value);

        public static readonly DependencyProperty LocationProperty =
            DependencyProperty.RegisterAttached(
                "Location", typeof(string), typeof(GridEx),
                new PropertyMetadata(string.Empty, (o, args) => EnsureParentSubscription((FrameworkElement)o)));
Пользоваться так:
<local:GridEx Background="Gray">
    <local:GridEx.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
    </local:GridEx.RowDefinitions>
    <local:GridEx.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </local:GridEx.ColumnDefinitions>
    <Rectangle Fill="Red"/>
    <Rectangle Fill="Green" local:GridEx.Location="next"/>
    <TextBlock Text="Working!" local:GridEx.Location="current"/>
    <Rectangle Fill="Yellow" local:GridEx.Location="1,1"/>
Результат:
Тут непонятно, от чего должен отталкиваться next и current
У меня они отталкиваются от ближайшего установленного через GridEx.Location значения
Если нужно, чтобы отталкивались от последней установленной каким угодно способом клетки, то нужно поменять в RecalcAttachedProperties:
if (location == string.Empty)
{
    currColumn = Grid.GetColumn(child);
    currRow = Grid.GetRow(child);
    continue;
}
а остальное всё то же вроде
 
03:00 - 16:0016:00 - 23:00

« first day (843 days earlier)      last day (2188 days later) »