Open source
Programming
.NET
C#
Comments 56
+1
Грац.
Пробовал простые формы накидывать, получается довольно удобно.
Есть какие то вещи, которые ещё явно нужны и будут в ближайшем релизе?
+3

Смотря для чего нужны. На десктопе сейчас разве что API для работы со шрифтами не хватает.


У нас пока в планах на 0.6 доделать deferred-рендеринг (который в отдельном потоке), переехать на Portable.Xaml (OmniXAML тормозной очень и хуже поддерживается), сделать нормальный превьювер для *nix-платформ и воткнуть его хотя бы в MonoDevelop, сделать уже наконец генерацию линуксовых пакетов и бандлов для OSX в один клик, сделать бакэнд на базе MonoMac.

+6

Будем его поддерживать. Он же по сути определяет перечень контролов и свойств, которые они должны иметь, не более того.

+1

Насколько сложно прикрутить туда альтернативный механизм биндингов? Моя попытка покопаться в дебрях биндингов WPF закончилась кучей внутренних методов которые непонятно что делают...


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

+1

Наша встроенная система работает на базе ReactiveExtensions. Альтернативный механизм биндингов прикручивается примерно так же как и к WPF-написанием этого самого механизма и реализацией соответствующего MarkupExtension.


Что именно имеется ввиду под "подпиской на изменения вызываемым кодом"?

0

Механизм, при котором вызывающий код устанавливает в статическом свойстве обработчик, который будет запомнен теми объектами, к которым он обращается и вызван при изменении любой зависимости. Еще называется "динамическое определение зависимостей".


Для биндинга он, возможно, несколько избыточен — но реализовывать вью-модель с ним довольно удобно.

0
В стандартной разметке это вполне можно сделать через Dependity Property, на который забинден объект. Другой вопрос, что этот код не отличается вменяемостью (место, в котором я ДЕЙСТВИТЕЛЬНО жалею об отсутствии препроцессора в C#)
0

Нельзя ли по-подробнее? Я не вполне понимаю что такое "Dependity Property, на который забинден объект".

0
— Где-нибудь как-нибудь устанавливаете DataContext элемента управления на экземпляр класса (пусть будет A)
— Добавляете DependencyProperty «Prop» типа B в класс A вот так:

public static readonly DependencyProperty PropProperty =
            DependencyProperty.Register("Prop", typeof(<B>),
            typeof(ActionPanel), new FrameworkPropertyMetadata(null, (DependencyObject d, DependencyPropertyChangedEventArgs e) => {
// Вот тут ваш callback
 }));

public B Prop 
{
	set { SetValue(PropProperty, value); }
    get { return (B)GetValue(PropProperty); }
}


— Биндите свойство в Xaml как вам нужно (если свойство меняется из интерфейса — скорее всего понадобится TwoWay binding) ( <local:A Prop="{Binding}" />)

P.S.: Да, я знаю, что код ужасен. Именно поэтому я жалею об отсутствии препроцессора: он помог бы обернуть бойлерплэйт во что-нибудь вменяемое.
0

И какое это имеет отношение к тому, что я писал?


Как это решение обобщить на случай произвольного числа зависимостей? Например, как вы предлагаете "забиндиться" на сумму элементов коллекции?

0
Всё, понял. Что неправильно понял. Можете подробнее описать, что бы хотите сделать? Вы имеете ввиду Dependency Injection?

Код, что я привёл, по сути кастомный сеттер свойства. А-ля public B Prop { set; get; }, но с поддержкой XAML, на случай, если вы хотите мгновенно реагировать на изменения в интерфейсе (например, обновлять по мере ввода текста результаты поиска)

0

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

0

Кажется, я понял что объяснил слишком непонятно. Попробую подробнее. //cc: Krypt


Вот у меня есть библиотека, которая умеет делать вот так (писал ее под впечатлением от MobX):


private IEnumerable<Foo> _foos;
public IEnumerable<Foo> Foos 
{
    get { return GetProperty(_foos); }
    set { SetProperty(ref _foos, value); }
}

public double Avg => Computed(() =>
{
    return Foos.Average(s => s.X);
});

Свойство здесь Avg будет пересчитываться при изменении коллекции Foo или изменении свойства X у любого объекта, который входит в эту коллекцию — при условии что коллекция и объект написаны аналогичным способом.


Интересует возможность прикрутить ее куда-нибудь напрямую без реализации INPC (реализовать INPC нетрудно — но при этом теряется ленивость). Для того, чтобы это сделать, нужна возможность оборачивать код биндинга в вызов функции из моей библиотеки.

0
Для использования в качестве элементов списка вы можете использовать такой код:
List.ItemsSource = Foos

Если вы хотите обновлять элементы из кода, то обновляемые поля должны быть INotifyPropertyChanged или ObservableCollection. Либо дёргать обновление вручную из кода, что наверняка возможно, но я не знаю как. Ибо никогда не использовал.

Но, впрочем, стоит уточнить, что C#/WPF не являются моей основной платформой уже лет 5 как. Так что я не последняя инстанция.

0

Эти INotifyPropertyChanged или ObservableCollection — это, по сути, и есть дерганье обновлений из кода вручную. Которое надоело.

0
Можно по-подробнее про реализациею соответствующего MarkupExtension? На WPF я уже второй раз натыкаюсь на невозможность подписаться на изменение свойства у объекта. Хотя бы на изменение DataContext.

На AvaloniaUI такая возможность есть?
0

В авалонии свойство DataContext является обычным StyledProperty (аналог DependencyProperty), так что на него можно спокойно биндиться.


Подписки из коробки работают на все свойства зарегистрированные через AvaloniaProperty и на свойства, уведомляющие о своём изменении через интерфейс INotifyPropertyChanged.


Если хотите вот прям свою систему, то наследуетесь от MarkupExtension и из ProvideValue возвращаете что-то реализующее интерфейс IBinding.

0
Это же вроде UWP, а не WPF. В классе System.Windows.DependencyObject я такого метода не нашел.
0
Разве можно добавить доп. метаданные через AddOwner для того типа, в котором DependencyProperty уже определено?
0
ну так я ж ссылку привел, есть перегрузка с параметром метаданных.
Собственно по ссылке:
The supplied metadata is merged with the property metadata for the dependency property as it exists on the base owner. Any characteristics that were specified in the original base metadata will persist. Only those characteristics that were specifically changed in the new metadata will override the characteristics of the base metadata. Some characteristics, such as DefaultValue, are replaced if they are specified in the new metadata. Others, such as PropertyChangedCallback, are combined.
+1
интересный проект, но боюсь что будущее за Xamarin.Forms

уже сейчас поддерживаются Mac, UWP, Android и iOS
+1

Авалония и формы — вещи ортогональные. В том плане, что у нас подход "рисуем всё сами и одинаково" (минус — гуй выглядит не "нативно", частично решается мимикрией через темы), а forms оборачивает нативные контролы (минусы — удачи с вёрсткой макета от дизайнера и весельем с реализацией хоть чего-то сложного или нестандартного для каждой из платформ в отдельности).


Каждый из подходов хорош для своих применений. Так что тут скорее будет интеграция одного с другим, а не наоборот. Причём на Android/iOS уже сейчас есть принципиальная возможность встраивать куски интерфейса на авалонии в forms, нужно только рендереры соответствующие написать. На досуге надо будет заняться

0
да, эта разница принципиальная.

а насколько производительность рисования самим отличается от WebView/Browser и электрона?
0

С браузером не сравнивали, но уже сейчас быстрее чем WPF на Windows на определённых сценариях (авалония поверх Direct2D начинается с 1:30).


И такой немаловажный момент. У нас (как во всех нормальных UI-тулкитах) есть виртуализация списков. В браузеры её не завезли и приходится изобретать криво работающие костыли. Соответственно на задачах "показать список на несколько тысяч элементов" работать будет шустрее, а памяти кушать на порядки меньше.

+1
<Window xmlns="https://github.com/avaloniaui" Title="Test app" WindowState="Maximized" MinWidth="500" MinHeight="300">
    <Grid Name="MainGrid">
        <Button Content="Button text" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="40,40,0,0" Width="201" Height="65"/>   
    </Grid> 
</Window>

Без Alignment работает как ожидается. Судя по всему канва отрисовки текста не понимает Aligment и считает что их нет.

+1

Что-то с Layout-ом перемудрили. Если сделать вот так, то работает.


<Window xmlns="https://github.com/avaloniaui" Title="Test app" WindowState="Maximized" MinWidth="500" MinHeight="300">
    <Grid Name="MainGrid">
        <Button Content="Button text" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="40,65,0,0" >
            <Border Width="201" Height="65">
                <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">Button Text</TextBlock>
            </Border>
        </Button>
    </Grid>
</Window>

Пойму, что там именно происходит и заведу issue.

+1

Да, работает. Спасибо. Чуть больше кода, но работает. В UWP моя разметка работает корректно.

0

Спасибо. Еще вопрос — CEFGlue компилит Chromium с поддержкой MP3\4? Или все равно приходится компилить Chromium с proprientary_codecs=true?

0
между прочим, мне или приснилось или MP3 больше не требует лицензию с 23 апреля 2017 в вики так написано
0

Это надо гуглу сказать. :) Хотя возможно вы и правы. Около трех недель назад, когда я собирал Chromium "крайний раз"
(

Заголовок спойлера
да я в курсе, про "крайний", но избавиться не могу

:)
поддержки MP3\4 не было. Сейчас скомпилирую еще раз, посмотрю…
0

Спасибо. Достаточно оперативно. В настоящий момент пытаюсь подружить мою сборку хромиума с AvaloniaUI и CEFGlue. :) В принципе понятно, что перспективы есть. Насколько хорошие — выясняю. Еще раз спасибо.

0

Насколько плохо (в какой-то степени :) работает CEFGlue? В текущем проекте в WinForms версии использую CefSharp3. Понемногу переношу проект в .NET core и браузер — критичный элемент.

0

Я оригинальный CEFGlue использовал в WinForms и в целом был доволен. Порт для авалонии, насколько я знаю, делался по-возможности построчным копированием с WPF. Имеет смысл попробовать его погонять и попинать автора порта, если есть какие-то проблемы. Ну и следует понимать, что сейчас это не коробочное решение, а в какой-то мере конструктор "собери сам". Порт стал возможен только недавно после появления инфраструктуры WritableBitmap.

0

Будем пробовать. Проект выглядит интересно. Спасибо большое. Теперь буду в issue писать. :) Ваш подход выглядит изящно и жизнеспособно (на первый взгляд ;).

0
1. А с темами как обстоят дела? Внешний вид кастомизируется? Встроенные системные темы не подхватываются?
2. Какие сценарии использования видите лично Вы? Т.е. если бы это был бы платный продукт, какая бы у вас была «бизнес модель» и «целевой потребитель» (кому бы продавали)?
+1

1) Есть штатная тема, которую можно заменить на свою и в которой можно заменить цвета. Мимикрию под конкретные ОС пока не делали и наврятли будем делать до версии 1.0, если, конечно, не найдётся желающих этим делом заняться.
2) В качестве платного продукта оно бы неплохо зашло на всякого рода встраиваемых устройствах (Avalonia+Linux кушают порядка 100 мегабайт (x86, fbdev, наш каталог контролов в качестве объекта замера) против полугигабайтного аппетита Windows for IoT), а так же в качестве UI для игр. Там наблюдается некоторый голод в плане хорошего UI, так что можно было бы продавать за хорошую цену.

0
А что с поддержкой Standard 2.0? Публичная версия 0.5 работает с стандартом 1.1. Планируется ли поддержка 2.0?
0

Стандарты же обратно совместимы. Переход на новую версию стандарта — это не расширение поддержки, а сужение.

0
Если я сделаю проект netstandard20, то добавить его в зависимости проекта авалонии не получится. Приходится создавать проект стандарта 1.1.
0
Студия 2017.4 так сказала. Я указал в настройках проекта версию стандарта 1.1, проект добавился. Версия авалонии 0.5.0.2, вроде (установлена через дополнение, о которой говорилось в статье выше).
0

Студия плохо умеет работать с нугетом и собственной системой проектов, нугет плохо умеет работать с собственной системой зависимостей. Так что надо победить тупость нугета и его политики nearest-wins указанием нужных версий зависимостей прямо у себя, тогда всё нормально ставится.

0
вот тут напрашивается конкретная инструкция и/или пример на github
0

Делаете


dotnet restore|grep Detected|sed 's/.*downgrade../<PackageReference Include="/'|sed 's/ from /" Version="/'|sed 's/ to.*/"\/>/'

получаете на выходе что-то типа:


<PackageReference Include="System.Collections" Version="4.3.0"/>
<PackageReference Include="System.Diagnostics.Debug" Version="4.3.0"/>
<PackageReference Include="System.IO" Version="4.3.0"/>
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0"/>
<PackageReference Include="System.Runtime.Extensions" Version="4.3.0"/>
<PackageReference Include="System.Runtime.InteropServices" Version="4.3.0"/>
<PackageReference Include="System.Text.Encoding" Version="4.3.0"/>
<PackageReference Include="System.Threading.Tasks" Version="4.3.0"/>
<PackageReference Include="System.Collections" Version="4.3.0"/>
<PackageReference Include="System.Diagnostics.Debug" Version="4.3.0"/>
<PackageReference Include="System.IO" Version="4.3.0"/>
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0"/>
<PackageReference Include="System.Runtime.Extensions" Version="4.3.0"/>
<PackageReference Include="System.Runtime.InteropServices" Version="4.3.0"/>
<PackageReference Include="System.Text.Encoding" Version="4.3.0"/>
<PackageReference Include="System.Threading.Tasks" Version="4.3.0"/>
<PackageReference Include="System.Collections" Version="4.3.0"/>
<PackageReference Include="System.Diagnostics.Debug" Version="4.3.0"/>
<PackageReference Include="System.IO" Version="4.3.0"/>
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0"/>
<PackageReference Include="System.Runtime.Extensions" Version="4.3.0"/>
<PackageReference Include="System.Runtime.InteropServices" Version="4.3.0"/>
<PackageReference Include="System.Text.Encoding" Version="4.3.0"/>
<PackageReference Include="System.Threading.Tasks" Version="4.3.0"/>
<PackageReference Include="System.Collections" Version="4.3.0"/>
<PackageReference Include="System.Diagnostics.Debug" Version="4.3.0"/>
<PackageReference Include="System.IO" Version="4.3.0"/>
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0"/>
<PackageReference Include="System.Runtime.Extensions" Version="4.3.0"/>
<PackageReference Include="System.Runtime.InteropServices" Version="4.3.0"/>
<PackageReference Include="System.Text.Encoding" Version="4.3.0"/>
<PackageReference Include="System.Threading.Tasks" Version="4.3.0"/>

Вставляете это в файл проекта, у нугета внезапно случается просветление и он начинает нормально ставить зависимости.

Only those users with full accounts are able to leave comments. , please.