Все записи автора Алексей Лосев

Мнение о книге "Педагогическая поэма"

Книга замечательна. Во-первых, она написана очень хорошо, и не смотря на жанр "производственный роман", это действительно художественное произведение. Если сравнивать книгу Макаренко с первой Целью, то я даже не знаю, кому бы я отдал пальму первенства по художественной составляющей. Очень интересно читать про двадцатые годы прошлого века, не в воспоминаниях или фантазиях конца двадцатого века, а от непосредственного участника событий.
По содержанию. Книга must read. Я очень сильно жалею, что не прочитал ее раньше. На живых примерах описываются реальные кейсы из управления. Слабый коллектив, сильный коллектив, промежуточный контроль, делегирование, здоровое соревнование. Все очень живо, доступно и с минимальной адаптацией применимо в работе. Ну и да, если кто читал отзывы, что педагогика по Макаренко, это в первую очередь наказания... То я вас разочарую, педагогика по Макаренко, это в первую очередь коллектив, общие цели, совместная работа и многое другое. А про наказания в книге тоже есть, например, воспитанник мог быть наказан за серьезный проступок тем, что... был оставлен в кабинете директора. Да, вот такое суровое наказание, да еще и применялось только к тем, кого директор действительно уважал.
Читать или нет? Как я уже написал выше - читать. Не только педагогам, но и всем кто имеет отношение к работе с людьми. Великолепная книга.

Привязка к ресурсам в зависимости от данных

Столкнулся с интересной задачей. Есть некоторая коллекция данных, которую надо отобразить в ItemsControl. У элементов данных есть два свойства: первое просто текст, а второе имя ресурса с картинкой которую необходимо показать. Т.е. в зависимости от данных в модели должен подгружаться тот или иной ресурс. Поискав решение быстро наткнулся на применение конвертора который ищет ресурс по имени следующим способом:

return Application.Current.FindResource(resourceName) as BitmapImage;

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


В рамках примера, я буду использовать простой класс с двумя свойствами:
public class Model
{
    public string Title { getset; }

    public string ResourceName { getset; }
}
Вот разметка формы:
<Window x:Class="WpfApplication4.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:WpfApplication4"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <BitmapImage x:Key="plus" UriSource="plus.png" />
        <BitmapImage x:Key="delete" UriSource="delete.png" />
        <local:NameToStyleConverter x:Key="NameToStyleConverter" />
    </Window.Resources>
    <Grid>
        <ItemsControl x:Name="icDemo">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Image Style="{Binding ResourceName,Converter={StaticResource NameToStyleConverter}}" />
                        <TextBlock Text="{Binding Title}" />
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>
А вот заполнение данными списка при загрузке:
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        Loaded += MainWindow_Loaded;
    }

    private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        List<Model> items = new List<Model>();
        items.Add(new Model() { Title = "Один", ResourceName = "plus" });
        items.Add(new Model() { Title = "Два", ResourceName = "plus" });
        items.Add(new Model() { Title = "Три", ResourceName = "delete" });
        items.Add(new Model() { Title = "Четыре", ResourceName = "plus" });
        items.Add(new Model() { Title = "Пять", ResourceName = "delete" });
        icDemo.ItemsSource = items;
    }
}
Как можно видеть из разметки, у контрола Image свойство Source не присваивается, а присваивается... Стиль! Ну а дальше все просто, получая имя ресурсы, мы конвертором создаем динамически стиль, в котором свойству Source присваиваем DynamicResource. Вот так:
public class NameToStyleConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Style result = null;
        var name = value?.ToString();
        if (!string.IsNullOrWhiteSpace(name))
        {
            result = new Style(typeof(Image));

            var dynamicResource = new DynamicResourceExtension(name);

            var setter = new Setter()
            {
                Property = Image.SourceProperty,
                Value = dynamicResource
            };
            result.Setters.Add(setter);

        }
        return result;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
Ну и вот так это выглядит:
Как я уже сказал, таким образом надо поступать, если в конверторе нельзя просто извлечь ресурсы из Application. Так, кстати, можно и другие свойства задавать, необязательно привязку к ресурсам.

Мнение о книге "Эссенциализм. Путь к простоте"

Чтобы не было недоразумений, несмотря на то, что в названии этой книги стоит Эссенциализм, она не про направление в философии науки которое сформировал Поппер. Также, про эту книгу нельзя сказать что она про GTD. А вот про что она?  Скорее всего, эта книга описания системы личной эффективности которую Грен МакКеон выработал и применяет.
Основная суть которой заключается в стремлении отказаться от ненужного и сконцентрироваться на важном. Каждая глава, это небольшой рассказ о том почему тема в ней поднимаемая важна. Ну а заинтересовав читателя автор предлагает то что у него сработало для достижения продекларированной крутотеньки. Ну и как у здравомыслящего человека в практические советы включено куча всего. Например, буфер и дерево реальности Голдрата, говорите "Нет" Хетча, про вырабатывание привычек, про здоровый сони и так далее.
Т.е. это больше обзор, чем глубокое погружение. Сработают ли эти методы у читающего? Если начнет применять все и сразу - то нет. Да и описаны они гораздо хуже, чем в специализированных книгах. Но в целом полезны, по крайней мере несколько я постараюсь добавить в свою копилку применяемых практик.
Читать ли книгу? Да, как минимум как обзор. Как максимум, если еще своей системы нет, как источник вдохновения и направление для создания такой системы.

Итоги года


Год был не скучный.



С точки зрения профессионального опыта, поучаствовал в разработке нескольких интересных проектов. Попробовал внедрять проектное управление не в своих проектах. Получил опыт экстренного найма персонала. С сентября по декабрь отдел разработки в Калуге вырос с двух до десяти человек. И это при том, что есть еще Питер и Москва (там, правда пока только аналитики, но все же), да и в январе выходят еще трое.
С точки зрения личной эффективности, мне кажется именно этот год можно считать первым, когда применяемая мной система уже кристаллизовалась, и подлежит в дальнейшем только доработкам по "принципу штанги".
С точки зрения преподавания (да, скучаю по этому делу), принимал участие в организации нескольких конференций, одну из которых проводили на базе Калуга-Астрал совместно с Microsoft. Провел несколько занятий в рамках внутреннего обучения для автотестировщиков. Заявился в качестве докладчика на несколько конференций на следующий год.
Но были в уходящем году и не очень приятные вещи, несколько человек меня сильно разочаровали. Были проблемы со здоровьем у членов семьи. Не успел вырубить весь лес на участке.
Но в целом год дал много возможностей и я надеюсь что лучшие из них я не упустил.
Всех с наступающим новым годом!

P.s. У нас сегодня на работе у большинства сотрудников отгул, в кабинете сидим я и Таня отвечающая за тестирование, да в соседнем кабинете три человека :) Так вот, не делайте так :)

DevOps — cкорость? Да, скорость

Если посмотреть на девяностые годы прошлого века, то они дали большое количество методологий (если кому больше нравиться фреймворков) разработки программного обеспечения: FDD (Feature driven development), Scrum, Rup, XP. Но самыми востребованными оказались не технические подходы, а ориентированные на людей. В 2001 году это все привело к появлению Agile-манифеста. Не надо нам качества, не надо нам поддержки изменений, дайте нам быстро то, на что можно посмотреть, а уж мы примем решение, что делать дальше. В настоящее время складывается ощущение, что социальные факторы себя исчерпали и для дальнейшего повышения скорости их уже не хватает. Подход, включающий не только «про людей», но и «про технологии», получил название DevOps. Давайте посмотрим на чем еще мы можем выиграть в скорости поставки полезности.

Продолжение статьи на Хабре.

Замена стандартной подсветки в TreeView

Пятница, голова уже не варит, максимум на что ее еще хватит написать ответ на очередной вопрос на форумах MSDN. Суть вопроса: нужно при выборе элемента в дереве не подсвечивать стандартное выделение всего TreeViewItem, а подсвечивать часть DataTemplate, который отвечает за показ элементов дерева. Т.е. сделать надо, чтобы выделение работало вот так, как на январе:

Интересно? Тогда идем под кат.



Первое с чего начнем, это с модели данных. Я особо усердствовать не буду и воспользуюсь, благо всего неделя до нового года, вот таким классом:
public class Model : DependencyObject
{
    public bool IsSelected
    {
        get { return (bool)GetValue(IsSelectedProperty); }
        set { SetValue(IsSelectedProperty, value); }
    }

    // Using a DependencyProperty as the backing store for IsSelected.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty IsSelectedProperty =
        DependencyProperty.Register("IsSelected"typeof(bool), typeof(Model), new PropertyMetadata(false));


    public string Name { getset; }

    public Model[] Children { getset; }

    public static Model[] DemoData
    {
        get
        {
            var result = new Model[1];
            result[0] = new Model() { Name = "Зима" };
            result[0].Children = new[] { new Model() { Name = "Декабрь" }, new Model() { Name = "Январь" }, new Model() { Name = "Февраль" } };
            return result;
        }
    }
}
Теперь переходим к разметке.
Добавляем в дерево загрузку данных:
<TreeView ItemsSource="{Binding Source={x:Static local:Model.DemoData}}">
Теперь убираем подсветку выбранной ячейки. Для этого меняем цвет фона выбранного элемента и цвет текста выбранного элемента:
<TreeView.Resources>
    <Style TargetType="TreeViewItem">
        <Style.Resources>
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black"/>
        </Style.Resources>
        <Setter Property="IsSelected" Value="{Binding IsSelected}" />
    </Style>
</TreeView.Resources>
Теперь, чтобы не заморачиваться с DataTriger-ами добавим простенький конвертер:
public class IsSelectedToBrushConverter : IValueConverter
{
    static Brush HighlightBrush = new SolidColorBrush(Colors.LightBlue);

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Brush result = null;
        if (value is bool && (bool)value)
        {
            result = HighlightBrush;
        }
        return result;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Подключаем этот конвертер в ресурсы окна:
<Window.Resources>
    <local:IsSelectedToBrushConverter x:Key="IsSelectedToBrushConverter" />
</Window.Resources>
Все, осталось сделать HierarchicalDataTemplate, в котором будет подсвечивать только то, что нам нужно:
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
    <StackPanel Orientation="Horizontal">
        <Image Source="Images/snowflake.PNG" Width="20" />
        <TextBlock Text="{Binding Name}" Background="{Binding IsSelected,Converter={StaticResource IsSelectedToBrushConverter}}" />
        <Image Source="Images/snowflake.PNG" Width="20" />
    </StackPanel>
</HierarchicalDataTemplate>
Как все это выглядит, можно посмотреть в картинке из заголовка поста.

Получение имени метода вызвавшего текущий метод

В C# 6 появилось новое ключевое слово nameof которое позволяет получить строку с именем члена класса, что позволяет существенно упростить написание, например, реализации INotifyPropertyChanged. Зачем он нужен я писал вот здесь. Под катом, я покажу как упростить вызов метода OnPropertyChanged. Ну и покажу какой замечательный атрибут появился в .Net Framework 4.5 благодаря которому, даже nameof больше не нужно.

Итак, немного напомню. У нас есть некоторый класс реализующий упомянутый интерфейс. В интерфейсе объявлено всего одно событие и нам нужно при изменении значений свойств его вызывать. Такой класс может иметь вид:


public class MyClass : INotifyPropertyChanged
{
    private string _myString;

    public string MyString
    {
        get
        {
            return _myString;
        }
        set
        {
            if (value != _myString)
            {
                _myString = value;
                OnPropertyChanged(nameof(MyString));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string p_propertyName)
    {
        PropertyChanged?.Invoke(thisnew PropertyChangedEventArgs(p_propertyName));
    }
}

Как видно, при вызове метода OnProeprtyChanged мы вынуждены передавать строку. Что может привести к тому, что свойство мы переименуем, через рефакторинг изменение распространиться везде кроме этой строки и об изменении свойства никто не узнает.
Решить эту проблему можно применением нового ключевого слова nameof , вот так:


public string MyString
{
    get
    {
        return _myString;
    }
    set
    {
        if (value != _myString)
        {
            _myString = value;
            OnPropertyChanged(nameof(MyString));
        }
    }
}

Но и это еще не все. С появлением атрибута [CallerMemberName], у нас есть возможность вообще ничего не передавать в этот метод, он сам будет узнавать имя члена класса который его вызвал:


public class MyClass : INotifyPropertyChanged
{
    private string _myString;
 
    public string MyString
    {
        get
        {
            return _myString;
        }
        set
        {
            if (value != _myString)
            {
                _myString = value;
                OnPropertyChanged();
            }
        }
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
 
    protected void OnPropertyChanged([CallerMemberNamestring p_propertyName = "")
    {
        PropertyChanged?.Invoke(thisnew PropertyChangedEventArgs(p_propertyName));
    }
}

Стало намного лучше.

Форумы MSDN

Почти два года назад, я публиковал заметку о том что рейтинг на форумах MSDN превысил 20000. Сегодня достигнута следующая планка в 30000:

За время прошедшее с регистрации на форуме прошло 4 года, я сменил несколько работ. Время от времени на форуме возникают разговоры что все, он умер и почти никому не нужен. Но вот эта картинка показывает, что как минимум моя динамика постоянна:
А постоянство, как известно, признак... скромности :)