LINQ: Добавляем возможность группировки следующих подряд элементов

Всем нам знаком стандартный LINQ-метод GroupBy(). Он позволяет на основе некоего селектора разложить элементы в последовательности по группам. К сожалению, мы не можем в селекторе указать такое нетривиальное условие, как нахождение элементов рядом. А именно это мне и нужно было. Поиск по StackOverflow не дал каких-либо приемлемых решений, и я, скрепя душой, сел изобретать свой велосипед. Ниже представляю код метода аналогичного GroupBy() с одним отличием: группировка происходит только для рядом стоящих элементов.

К примеру, есть последовательность:
1 1 1 2 2 2 2 1 1 1 1 4 4 4 4 2 2 2

После группировки хотим получить следующие группы (в каждой строке по группе):
1 1 1
2 2 2 2
1 1 1 1
4 4 4 4
2 2 2

Читать далее

Способ поместить null-элемент в ComboBox

В каких случаях может понадобиться включить в коллекцию null? Ну, например, пользователь должен выбрать в ComboBox какой-то из пунктов и один из них должен означать, что выбор сделан не был. В code behind в таком случае мы ждём возврата значения null, а со стороны WPF пускай выглядит как некий пункт «Пусто» или «Нет значения».

К слову, встречал разные мнения по правомерности такого подхода. Некоторые считают, что null — это отсутствие значения и не должно использоваться. По первому пункту они правы — да это отсутствие значения, по второму — не согласен, null несёт смысловую информацию как раз этого отсутствия значения. Это видится естественным и повсеместно используется в .NET.

С моральной стороной разобрались, перейдём к практической. В чём же сложность такого подхода?

Читать далее

UniformImage: Изменение пропорций картинки без деформации содержимого по краям

В идеальном мире, по версии Microsoft, дизайнеры творят интерфейс в Expression Blend, а программисты пишут бэкенд на C#. В реальности же дизайнеры творят в Photoshop, а программисты ломают голову как вот эту красивую кнопку сконвертировать в XAML, да так чтобы без большого количества костылей. Многие добиваются в этом выдающихся результатов. Стоит только слегка поискать и в сети найдётся куча вариантов, как можно из элементов WPF собрать довольно сложные дизайнерские решения. К сожалению, пару раз так повозившись и оценив затраты по времени понимаешь, что оно того не стоит, проще взять исходный элемент из нарезки как есть, т.е. в виде изображения. И такой вариант, как по мне, является наилучшим с точки зрения продуктивности, однако есть одно НО.

Картинкам часто нельзя изменить пропорции. Края изображения сильно сжимаются с одной стороны и растягиваются с другой. К примеру, дизайнер прислал нам изображения кнопки:
Вставив её в проект и слегка изменив пропорции получим следующую непотребщину:
Встаёт вопрос, как при ресайзе изображения сохранить края в таком виде, как предполагал дизайнер?

Читать далее

Обрезание содержимого Border с закруглёнными краями

Если поместить содержимое внутрь элемента Border и задать закругленные края, то оно всё равно будет вылезать за пределы элемента.
В данном случае, не спасёт даже свойство ClipToBounds, так как оно обрезает содержимое лишь по границам элемента не учитывая закругленных краёв.

Решение проблемы довольно простое. У любого элемента WPF есть свойство OpacityMask, внутри которого можно задать маску непрозрачности элемента. Логично было бы, в нашем случае, задать маску точно такую же как и сам элемент Border. К сожалению, привязать к маске непосредственно оригинальный Border не получится, однако можно просто создать очень похожий Border. Всего лишь надо, чтобы у элементов совпадали свойства CornerRadius, Width и Height, к примеру, через привязку.

В результате, получаем довольно короткое решение средствами XAML:

<Border CornerRadius="30" Background="Green">
    <Border.OpacityMask>
        <VisualBrush>
            <VisualBrush.Visual>
                <Border 
                    Background="Black"
                    CornerRadius="{Binding CornerRadius, RelativeSource={RelativeSource FindAncestor, AncestorType=Border}}"
                    Width="{Binding ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType=Border}}"
                    Height="{Binding ActualHeight, RelativeSource={RelativeSource FindAncestor, AncestorType=Border}}"
                    />
            </VisualBrush.Visual>
        </VisualBrush>
    </Border.OpacityMask>
    <TextBlock Text="ТЕКСТ ТЕКСТ ТЕКСТ ТЕКСТ ТЕКСТ ТЕКСТ ТЕКСТ ТЕКСТ ТЕКСТ" />
</Border>

Результат:

Задание useLegacyV2RuntimeActivationPolicy во время выполнения

Проблема загрузки сборок скомпилированных под устаревший CLR давно известна. Старые библиотеки отказываются работать в CLR 4 и выше, если принудительно не задать в app.config разрешение на выполнение этих сборок в новом райнтайме:

<configuration>
  <startup useLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntime version="v4.0"/>
  </startup>
</configuration>

Без этой настройки получим исключение FileLoadException:
Сборка для смешанного режима построена на основе версии «v2.0.50727» среды выполнения и не может быть загружена в среде выполнения 4.0 без дополнительных конфигурационных данных.

Что же делать, если нет желания или возможности таскать с собой app.config?
К счастью, можно задать параметр useLegacyV2RuntimeActivationPolicy во время выполнения.

Читать далее

Генерация случайного простого числа

На днях понадобилось найти код генерации случайного простого числа. Как ни странно, в сети на этот счет полностью готового решения не нашёл. Максимум, народ выкладывал оптимизированную проверку на простоту числа.

Пришлось написать небольшой класс для генерации. Всё что делает — генерирует случайное число и сдвигает его в большую сторону до ближайшего простого. Работает, относительно, шустро, генерирует UInt32, но это не принципиально. Самой затратной операцией оказалось, как ни странно, деление с остатком. 🙂

public class PrimeNumberGenerator
{
    private readonly Random _random = new Random();

    public uint Generate()
    {
        var numberBytes = new byte[4];
        _random.NextBytes(numberBytes);
        uint number = BitConverter.ToUInt32(numberBytes, 0);

        while (!IsPrime(number))
        {
            unchecked
            {
                number++;
            }
        }
        return number;
    }

    private static bool IsPrime(uint number)
    {
        if ((number & 1) == 0) return (number == 2);

        var limit = (uint)Math.Sqrt(number);
        for (uint i = 3; i <= limit; i += 2)
        {
            if ((number % i) == 0) return false;
        }
        return true;
    }
}

Использование:

var generator = new PrimeNumberGenerator();
uint prime = generator.Generate();

WPF: Привязка для свойств отличных от свойств зависимостей

Введение

WPF — замечательная технология, которую, не смотря на все ее недостатки, очень люблю. Тем не менее, часто приходится писать не разметку, а код, который помогает первой работать как надо. Хотелось бы этого избегать и писать чистый XAML, но до сих пор ни одно мое приложение сложнее простого не обходилось без различных хелперов (классов-помощников), написанных на C#. К счастью, есть распространенные случаи, где можно одним хелпером решить сразу группу проблем.

Речь ниже пойдет о привязке в обычных свойствах визуальных элементов, которые не являются свойствами зависимостей (dependecy properties). Штатными средствами WPF этого сделать не получится. Ко всему прочему, мы не можем узнать об изменениях такого свойства, кроме как подписавшись на специальное событие, что противоречит шаблону MVVM. Такие события для каждого свойства могут быть свои. Самый распространенный пример — это PasswordBox и его свойство Password. Так у нас сделать не получится:

<PasswordBox Password={Binding OtherProperty} />

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

Читать далее

CLR via C#

CLR via C#Давеча закончил читать прекрасную книгу по .NET/C# от тов. Рихтера — «CLR via C#».
Книга — отличный экскурс в глубины шарпа и CLR. Стоит заметить, Рихтер увлекается копанием в дебрях, любит экономить на спичках и расписывать как это делает. Отсюда и толщина книженции, из которой не напрягаясь можно половину выкинуть. Тем не менее, книга отличная и читать стоит.

Ниже идет список заметок, которые сделал во время чтения.

Читать далее

Блог, появись!

Вот и создал блог. Долго думал, но никак не мог собраться и сделать. Буду писать сюда как мысли, так и интересные факты найденные на просторах сети, книг, головы. Речь про стек технологий .NET, конкретно C# и WPF. В будущем, может, и ASP.NET и прочим за что возьмусь. Есть пара идей заметок по Visual Studio и ReSharper.