Страницы

Поиск по вопросам

пятница, 28 июня 2019 г.

Как сделать выпадающий список произвольной формы?

Здравствуйте, хотел бы узнать, как решить эту проблему. Есть элемент Expander, который имеет свой стандартный стиль. Использование Data или Path даёт возможно изменить внешний вид окна и саму кнопку для активации этого выпадающего списка при использование Template. Как это возможно сделать и также чтобы выпадающий список был ровно под кнопкой? К примеру: вызов окна в Skype Данные о качестве связи(громкость и тд.).

Note: знаю, как использовать Data и Path.


Ответ

Если надо можно будет дорисовать ^ самому, так как Path точно прорисован по контуру.

Activity has been destroyed во время FragmentTransaction.commit()

Пишу небольшую программку для андроида. Мне нужно создать программно фрагменты. Для этого я написал отдельный класс с функциями FragmentWorkHelper.java:
public class FragmentWorkHelper extends FragmentActivity {
FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction ft; public MainTopCompositeFragment mtcf = new MainTopCompositeFragment(); public MainCentralCompositeFragment mccf = new MainCentralCompositeFragment(); public MainBottomCompositeFragment mbcf = new MainBottomCompositeFragment();
public void ReplaceFrag(Fragment f, int container){ ft = fragmentManager.beginTransaction(); ft.replace(container, f); ft.commit(); }
public void RemoveFrag(Fragment f){ ft = fragmentManager.beginTransaction(); ft.remove(f); ft.commit(); }
public void AddFrag(Fragment f, int container){ ft = fragmentManager.beginTransaction(); ft.add(container, f); ft.commit(); }
public void CreateFrag(){ ft = fragmentManager.beginTransaction(); ft.add(R.id.main_top_fragment, mtcf); ft.add(R.id.main_central_fragment, mccf); ft.add(R.id.main_bottom_fragment, mbcf); ft.commit(); } }
Вызываю функции этого класса из различных мест программы, например в OnCreate() в MainActivity.java:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); FragmentWorkHelper fwh = new FragmentWorkHelper(); fwh.CreateFrag(); }
Но в итоге получаю вот что:
Process: developers.com.polygon, PID: 27767 java.lang.RuntimeException: Unable to start activity ComponentInfo{developers.com.polygon/developers.com.polygon.MainActivity}: java.lang.IllegalStateException: Activity has been destroyed at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2693) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2758) at android.app.ActivityThread.access$900(ActivityThread.java:177) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1448) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:145) at android.app.ActivityThread.main(ActivityThread.java:5942) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1400) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195) Caused by: java.lang.IllegalStateException: Activity has been destroyed at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1399) at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:637) at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:616) at developers.com.polygon.FragmentWorkHelper.CreateFrag(FragmentWorkHelper.java:43) at developers.com.polygon.MainActivity.onCreate(MainActivity.java:51) at android.app.Activity.performCreate(Activity.java:6289) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
           В чем беда? Почему активити уничтожается? Я пытался засунуть функции в MainActivity, но выходит та же самая ошибка. Очень нужна помощь.


Ответ

getSupportFragmentManager возвращает менеджер для взаимодействия фрагментов с activity из которой он вызван. Соответственно ваш хелпер бесполезен т.к. он может управлять фрагментами только внутри своей activity, а не во всех activity вашего приложения. Если хелпер вам так нужен то сделайте так

public class FragmentWorkHelper{
private final FragmentActivity activity;
public FragmentWorkHelper(FragmentActivity activity) { this.activity = activity; }
public void replaceFrag(Fragment f, int container){ FragmentTransacion ft = activity.getSupportFragmentManager().beginTransaction(); //some work }
public void removeFrag(Fragment f){ FragmentTransacion ft = activity.getSupportFragmentManager().beginTransaction(); //some work }
public void addFrag(Fragment f, int container){ FragmentTransacion ft = activity.getSupportFragmentManager().beginTransaction(); //some work } }
И тогда в activity в методе onCreate() создавайте экземпляр этого хелпера FragmentWorkHelper helper = new FragmentWorkHelper(this).

Проблема с сохранением canvas

Есть div, из содержимого этого div формируется canvas,потом я пытаюсь сохранить это в png
$("#s_img1").click(function (){
html2canvas($("#tableWrap"), { onrendered: function(canvas) {
theCanvas = canvas; document.body.appendChild(canvas);
$("canvas").attr("id", "canv"); $("#img-out").append(canvas);
} }); var data = document.getElementById("canv").toDataURL();
$.post("process.php", { imageData : data }, function(data) { window.location = data; });
var myCanvas = $(document).find('#canv'); var myImg = myCanvas.get(0).toDataURL();

alert(myImg);
});
Проблема в том,что консоль дает ошибку на toDataURL();
Uncaught TypeError: Cannot read property 'toDataURL' of undefined
Подскажите в чем проблема? Вот process.php
$data = substr($_POST['imageData'], strpos($_POST['imageData'], ",") + 1); $decodedData = base64_decode($data); $fp = fopen("canvas.png", 'wb'); fwrite($fp, $decodedData); fclose(); echo "/canvas.png";
Тут html








Right click to save me!


Ответ

Проблема том, что при вызове var myCanvas = $(document).find('#canv'); элемент canv еще не создано. Так будет работать:
function CallPost(postdatа) {
$.post("process.php", {imageData: postdatа}) .done(function (data) { window.location = 'canvas.png'; }); }
$(document).ready(function() { $("#s_img1").click(function () { html2canvas($("#tableWrap"), { onrendered: function (canvas) { CallPost(canvas.toDataURL()); } }); }); });

Динамическое добавление полей форм jQuery

var count_input = 0; function addFiel () { var telnum = parseInt($('#add_field_area').find('div.add:last').attr('id').slice(3))+1; $('div#add_field_area').append('

'); } function addD () { var tel = parseInt($('#ad_f').find('div.dob:last').attr('id').slice(3))+1; $('div#ad_f').append('
'); } function deleteField (id) { $('div#add'+id).remove(); } input { height: 20px; margin: 5px; width:400px; } .addbutton { text-align: center; vertical-align:middle; font-size: 13px; width: 283px; border: 1px solid #70A9FD; -webkit-border-radius: 7px; -moz-border-radius: 7px; border-radius: 7px; cursor: pointer; margin: 2px 0 0 110px; color: #326DC5; padding: 4px; background-color:#BED6FF; } .deletebutton { width: 20px; height: 22px; cursor: pointer; margin: 5px; display:inline-block; background: url(delete.png) repeat; background-position: center center; background-repeat: no-repeat; position:absolute; top: 1px; left: 480px; } .add { position:relative; }
Добавить новое поле

При нажатии на кнопку ДОБАВИТЬ НОВОЕ ПОЛЕ, добавляем два поля. После этого нажимаем на кнопку ЕЩЕ НОВОЕ для поля №2 и добавление происходит в поле №1 и поле №2. Как сделать чтоб каждому полю соответствовали свои кнопки?


Ответ

Использовать всплытие событий и подниматься до нужного контейнера:
$(document).on('click', ".container .add-group", function() { var container = $(this).closest(".container"); container.append( $("#group-template").html() .replace(/\{\{g\}\}/g, container.children(".group").last().data("i") + 1 || 1) ); }).on('click', ".group .add-field", function() { var group = $(this).closest(".group"); group.append( $("#field-template").html() .replace(/\{\{g\}\}/g, group.data("i")) .replace(/\{\{f\}\}/g, group.children(".field").last().data("i") + 1 || 1) ); }).on('click', ".group .field .remove-field", function() { $(this).closest(".field").remove(); }); section { border: 1px solid; margin: 1em 0; }


PS: Лучше воспользоваться нормальным шаблонизатором.

Прочитать с середины файл без чтения его начала на Rust'е

let f = File::open("file").unwrap(); let reader = BufReader::new(f).seek(io::SeekFrom::Start(2)); for b in reader.iter().next() { println!("{}", b); }
Выводит то, что находится внутри io::SeekFrom::Start, т.е. 2.


Ответ

Какой-то странный цикл у вас. По идее должно быть как-то так:
let f = File::open("file").unwrap(); let mut reader = BufReader::new(f); reader.seek(io::SeekFrom::Start(2)).unwrap(); for b in reader.bytes() { println!("{}", b); }
Метод seek() возвращает Result, то есть новую позицию в файле. Он вызывается на &mut self, значит reader должен быть mut, иначе не заработает.
Что делает ваш код: вы открываете файл и смещаете указатель на 2 байта, сохраняя Result в reader. Потом вы преобразовываете Result в итератор с помощью iter() и вызываете на итераторе next(), получаете Option, равный Some(2). А потом по опции итерируете (Option<_> реализует IntoIterator, так что этому типу можно итерировать). Итератор весело выдаёт один элемент — 2.
Чтобы избежать подобных ошибок в будущем, внимательно читайте документацию на используемые трейты и типы: ни в трейте Read, ни в типе BufReader нет метода iter(), однако в Read есть метод bytes(), который вам был нужен. А вот метод Seek::seek возвращает Result. Кроме того стоит больше прочитать про интерфейс итераторов, так как вы, судя по всему, до конца не поняли эту идею, раз вызываете на итераторе метод next() явно.

Реализация синглтона с многократным освобождением ресурсов

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


Ответ

А в чём проблема? Ну окружите весь доступ мьютексом. Поскольку вам нужна логика реинициализации, простое решение с Lazy-свойствами не проходит.
public sealed class Singleton { // классическая реализация из статьи Jon Skeet'а // http://csharpindepth.com/articles/general/singleton.aspx private static readonly Lazy lazy = new Lazy(() => new Singleton());
public static Singleton Instance { get { return lazy.Value; } }
private Singleton() { }
/////////////////// ленивые свойства /////////////////// object accessMutex = new object();
string lazyProperty; public string LazyProperty { get { lock (accessMutex) return lazyProperty ?? (lazyProperty = CreateLazyProperty()); } }
public void Reset() { lock (accessMutex) { lazyProperty = null; // обнулите остальные свойства, освободите IDisposable-ресурсы } }
string CreateLazyProperty() { ... } }

Определить значение элемента «спиральной матрицы» по его координатам

Недавно был вопрос об инициализации массива спиральной матрицей. Хотя предложенные решения его решают, интересно решить эту задачу без использования памяти под массив, а именно:
Написать метод getNum(int s, int x, int y), который принимает три целых параметра — размер квадратной матрицы (s) и координаты позиции в этой матрице (x, y от 0 до s-1) и возвращает число от 1 до s*s, которое должно стоять в соответствующей ячейке «спиральной матрицы» (сматывающейся от левого-верхнего угла к центру по часовой стрелке).
Тогда задача вывода данной матрицы на экран должна свестись к такому коду (никакой массив не нужен):
for (int y = 0; y < s; y++) { for (int x = 0; x < s; x++) { System.out.printf("%4d", getNum(s, x, y)); } System.out.println(); }
Кроме того можно вообще выводить огромные матрицы, в UI-окошке и скроллить мышкой, быстро отрисовывая только видимую часть.
Как же реализовать такой метод?
Решения на других языках тоже принимаются.


Ответ

Для начала переведём входные координаты x и y в систему координат относительно центра матрицы. Так как размер может быть чётным или нечётным, удвоим координаты, чтобы не возиться с половинками:
x = 2 * x - s + 1; y = 2 * y - s + 1;
Скажем, для матрицы 5×5 возможные значения x и y будут -4, -2, 0, 2, 4. А для матрицы 6×6 — -5, -3, -1, 1, 3, 5.
Дальше определим, на каком квадрате от центра лежит текущая точка. Это просто максимум модуля обеих координат:
int n = Math.max(Math.abs(x), Math.abs(y));
Скажем, для квадрата 5×5 значения будут такие:
4 4 4 4 *4 4 2 2 *2 4 4 2 *0 2 4 4 2 2 2 4 4 4 4 4 4
Заметим, что внутри текущего квадрата (n-1)*(n-1) записей. Попробуем определить, какое число должно быть на правой-верхней диагонали. Надо из квадрата s*s вычесть квадрат n*n и посмотреть, что получается. Оказывается, надо ещё n вычесть. Вот значения s*s-n*n-n для квадрата 5×5:
5 5 5 5 *5 5 19 19 *19 5 5 19 *25 19 5 5 19 19 19 5 5 5 5 5 5
Ура, диагональ получили. С чётной стороной это тоже верно. Теперь посчитаем расстояние от этой диагонали с учётом знака:
int p = (y + x) / 2;
Прибавим это расстояние к нашему s*s - n*n - n, получим:
1 2 3 4 5 2 17 18 19 6 3 18 25 20 7 4 19 20 21 8 5 6 7 8 9
Отлично, теперь весь правый-верхний треугольник мы правильно выдаём. Чтобы починить левый-нижний, надо для него заменить p на 2*n-p. Точка лежит в левом-нижнем треугольнике, если x < y
if (x < y) p = 2 * n - p;
Вот полный код:
public static int getNum(int s, int x, int y) { x = 2 * x - s + 1; y = 2 * y - s + 1; int n = Math.max(Math.abs(x), Math.abs(y)); int p = (x + y) / 2; if (x < y) p = 2 * n - p; return s * s - n * n - n + p; }

Нестандартная сериализация/десериализация при помощи newtonsoft json

Есть следующие классы:
public sealed class User { public int Id { get; set; } public Schema Extensions { get; set; } }
public sealed class UserProperty { public string Id { get; set; } public object Value { get; set; } }
public sealed class Schema { public string Name { get; set; } public List Properties { get; set; } }
Задается вот так:
var user = new User { Id = 1, Extensions = new Schema { Name = "urn:scim:schemas:custom:1.0", Properties = new List { new UserProperty { Id = "A", Value = 1} }
} };
Необходимо получить json следующего вида:
{ "Id": 1, "urn:scim:schemas:custom:1.0": { "A": 1 } }
Как это можно сделать при помощи библиотеки newtonsoft? И соответственно потом десериализовать в структуры, описанные выше?


Ответ

Вам нужен JsonExtensionDataAttribute. Но тут есть ограничение - насколько я понимаю, он может быть только типа, реализующего IDictionary

Cast оператор и шаблонные функции

Предположим у меня есть два шаблонных типа: основной, который будет везде использоваться и вспомогательный, для нужд реализации. И я хочу объявить функцию которая принимает основной тип.
template struct Usefull;
template struct Helper { Helper(T i) : v(i) {}
T v;
operator Usefull() { return Usefull(v); } };
template struct Usefull { Usefull(T i) : h(i) {}
Helper h; void print() { std::cout << h.v << std::endl; } };
template void foo(Usefull b) { b.print(); }
И я хочу использовать это вот так:
int main() { Usefull x(42); foo(x.h); }
Но возникает ошибка компиляции:
template argument deduction/substitution failed: 'Helper' is not derived from 'Usefull'
Использовать static_cast> не желательно, менять или перегружать foo тоже не охота. Есть ли какие-то еще способы заставить Helper хорошо и неявно преобразовываться в Useful?
То есть пользователь не должен знать с чем он работает на самом деле, Useful и Helper для него должны вести себя одинаково. Может здесь можно использовать наследование, но я не приложу ума как это организовать.


Ответ

Согласно примечанию к параграфу №4 в разделе 14.8.2.1 Deducing template arguments from a function call стандарта C++
[ Note: as specified in 14.8.1, implicit conversions will be performed on a function argument to convert it to the type of the corresponding function parameter if the parameter contains no template-parameters that participate in template argument deduction. Such conversions are also allowed, in addition to the ones described in the preceding list. —end note ]
В вашем случае соответствующий параметр функции содержит шаблонный параметр, который участвует в выведении шаблонного аргумента. Поэтому вам придется явно указать шаблонный аргумент или явно использовать приведение типов. Например
Usefull x(42);
foo(x.h); foo( static_cast>( x.h ));

MySQL ORDER BY приближенное значение

Доброго времени суток! Сразу приведу пример чтобы было понятно. На сайте стандартный поиск сортирует по title (названию новости). У нас есть например 2 новости "семь" и "восемь" и если ввести "семь" то выведет в первую очередь "восемь", т.к. у нас сортировка по алфавиту. Как написать поиск более точный? PHP


Ответ

Если конкретно надо вот прям сначала те которые начинаются, а потом которые только содержат, то
WHERE title LIKE 'семь%' ORDER BY title UNION SELECT ... WHERE title LIKE '%семь%' ORDER BY title
Но вообще то что тебе нужно называется полнотекстовый поиск

QByteArray во float

Есть QByteArray, в котором лежат несколько float. Нужно их оттуда вынуть и записать в соответствующие переменные. Пока единственным решением нашел копирование области памяти с помощью memcpy:
float f1, f2; memcpy(&f1, byteArray.data(), sizeof(float)); memcpy(&f2, byteArray.data()+sizeof(float), sizeof(float));
Если пытаться использовать QDataStream, то ничего путного не выходит, т.к. он пытается считать не 4 байта, а 8. Какие решения еще можно найти?


Ответ

Используйте класс QDataStream и setFloatingPointPrecision()
QByteArray arr; float f1, f2; QDataStream ds(&arr, QIODevice::ReadOnly); ds.setFloatingPointPrecision(QDataStream::SinglePrecision); ds >> f1 >> f2;
Чтобы попеременно читать double и float, нужно переключать режим точности.
QByteArray arr; float f1; double f2; QDataStream ds(&arr, QIODevice::ReadOnly); ds.setFloatingPointPrecision(QDataStream::SinglePrecision); ds >> f1; ds.setFloatingPointPrecision(QDataStream::DoublePrecision); ds >> f2;
Либо можно читать "сырые" байты:
QDataStream ds(&arr, QIODevice::ReadOnly); ds.readRawData(reinterpret_cast(&f1), sizeof(f1)); ds.readRawData(reinterpret_cast(&f2), sizeof(f2));

Выделить в текущей строке всё с первого непробельного символа до последнего

Допустим, у меня есть строчка кода с отступом
promocode.discount_amount
и курсор где-нибудь в районе слова discount_amount
Чтобы выделить всё важное на строке, например, для заворачивания в скобки, я набираю
$v^
Уверен, есть более быстрое решение, но никак не могу его найти.


Ответ

Поправка: чтобы переместиться к последнему непробельному символу, надо использовать g_, а не $
В вашем примере сработает viW (inner WORD, см. :help text-objects). Однако, в общем случае, когда в середине строки могут встречаться пробельные символы, это работать не будет. К сожалению в Vim нет стандартного text-object-а для того, что нам нужно.
Тут нам на помощь придут mapping-и. Будем использовать для нашего «объекта» буквосочетание il (inner line). Никто не мешает использовать один символ, но тогда скорее придется пожертвовать соответствующей стандартной командой. Следующий mapping для visual mode позволяет сделать то, что нам нужно:
:vnoremap il :normal! ^vg_
Теперь при нажатии vil будет выделена «важная» часть строки.
Опционально: сейчас il работает только в visual mode. Можно заставить его работать со всеми командами Vim, которые ожидают на вход movement или text-object (d, y, c, и т.д.). Для этого используются mapping-и для Operator-pending mode (см. :help omap-info):
" внимание, в правой части используется mapping il, который мы определили выше :onoremap il :normal vil
Теперь, в частности, yil копирует «важную» часть строки, а dil — удаляет ее.
Подробнее почитать, как и почему это работает можно в:
Главе Operator-Pending Mappings (и след.) в книге Learn Vimscript the Hard Way Статье Creating new text objects Стандартном :help

Как искать похожие изображения между двумя папками?

Есть ли возможность у findimagedupes сравнивать изображения в одной папке с другой?
Например, в одной папке 100 изображений, и в другой столько же. В первой папке есть одно изображение, более, чем на 85%, похожее на одно изображение в другой папке.
Я пробовал делать так:
findimagedupes -t 85 "первая_папка/*" "вторая_папка/*"
но дело в том, что он показывает совпадения, которые нашлись в первой папке и/или во второй. А надо, чтобы сообщал, что «найдено изображение в папке первая_папка, которое совпадает с изображением во вторая_папка»


Ответ

можно в цикле перебрать все пары файлов:
$ for f1 in первый_каталог/*; do \ for f2 in второй_каталог/*; do \ findimagedupes -t 85 $f1 $f2; done; done

если же требуется, чтобы в выводимых строках пары файлов не были перемешаны (первым может идти файл то из первого, то из второго каталога), то можно каждую строку отсортировать, воспользовавшись возможностью программы findimagedupes передавать получаемые строки на обработку указанному скрипту (см. man findimagedupes):
$ for f1 in первый_каталог/*; do \ for f2 in второй_каталог/*; do \ findimagedupes -t 85 -i \ 'VIEW(){ for f in "$@"; do echo $f; done | sort | xargs echo; }' -- \ $f1 $f2; done; done

такой перебор каждого-с-каждым довольно ресурсоёмок («отпечатки»-fingerprints вычисляются при каждом запуске), поэтому для большей оптимальности следует либо дополнить нужной функциональностью саму программу, либо, вызывая её для всех файлов сразу, несколько усложнить скрипт, передаваемый программе опцией -i

обновление
«усложнил» скрипт:
#!/bin/bash
d1=$(realpath $1) d2=$(realpath $2)
e1=$(echo $d1 | sed 's,/,\\/,g')
findimagedupes -t 85 -i 'VIEW() { n1=$(for f in "$@"; do echo $f; done \ | sed -n "/^'$e1'/{p;q}"); n2=$(for f in "$@"; do echo $f; done \ | grep "^'$d2'" | xargs echo); if [ -n "$n1" -a "$n2" ]; then \ for f in "$@"; do echo $f; done | sed -n "/^'$e1'/!{s|^|$n1 |;p}"; fi; \ }' $d1/* $d2/*
вызывается он с двумя параметрами: первый_каталог второй_каталог (без каких-либо масок, просто пути к каталогам). для каждой строки, генерируемой программой, он оставляет только один файл из первого каталога (первый встретившийся), но разбивает её на несколько строк так, чтобы в каждой получившейся строке было только по одному файлу из второго каталога.
например, строку dir1/file1 dir1/file2 dir2/file1 dir2/file2 он заменит на две строки:
dir1/file1 dir2/file1 dir1/file1 dir2/file2
и, конечно, строки, в которых присутствуют только файлы из первого или только из второго каталога, игнорируются.

Странная ошибка в XAML: ошибка при конвертации типа при присваивании через StaticResource

Не знал как коротко описать суть проблемы.
Вот код xaml

Вот код c# класса LocalizedString
public class LocalizedString : IComparable, ICloneable, IEnumerable, IEquatable, IEquatable { public LocalizedString(string str) { OriginalString = str; }
public LocalizedString() { OriginalString = ""; }
public string OriginalString { get; set; }
public string LocalizeString { get { return InteractiveLocalizer.Localize(OriginalString); } }
public override string ToString() { return LocalizeString; }
public int CompareTo(object obj) { if (obj == null) return 1; var str = obj as string; if (str != null) return LocalizeString.CompareTo(str); var lstr = obj as LocalizedString; if (lstr != null) return LocalizeString.CompareTo(lstr.LocalizeString); throw new ArgumentException("LocalizedDtring: Bad type"); }
public object Clone() { return new LocalizedString(OriginalString); }
public IEnumerator GetEnumerator() { return LocalizeString.GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
public bool Equals(string other) { return other == LocalizeString || other == OriginalString; }
public bool Equals(LocalizedString other) { return OriginalString == other.OriginalString; }
public static implicit operator LocalizedString(string v) { return new LocalizedString(v); }
public static explicit operator String(LocalizedString ls) { return ls.LocalizeString; } }
В данном случае LocalizedString ворачивает ту же самую строку, что и получает "qwe". Я это и ожидал, но во время выполнения прога падает с исключением. Вот текст
"qwe" не является допустимым значением для свойства "Text".
Как так?
Ошибка есть и во время компиляции (хоть она и позволяет запуститься приложению). Вот ее текст
Не удается применить объект типа "LocalizerLib.LocalizedString" к свойству, для которого требуется тип "System.String".
В классе определены операторы implict и explict. Чего еще не хватает, чтобы я мог вместо string вставить свой тип?


Ответ

XAML игноирирует операторы приведения типа (хоть явные, хоть неявные). Разнообразные конвертеры используются, например, для преобразования результатов биндинга. И даже в этом случае операторы не используются, предпочтение отдаётся ассоциированному TypeConverter (который, впрочем, по умолчанию поддерживает преобразование к строке и просто вызывает ToString). Однако при использовании ресурсов никакой конвертации не производится. Ваш код приводит к вызову:
object res = new LocalizedString("foo"); fooTextBlock.Text = res;
С очевидными последствиями.
Могу предложить несколько путей:
Вместо странных костылей с ресурсами можно воспользоваться расширениями разметки MarkupExtension. Метод ProvideValue может возвращать произвольный тип и даже учитывать, какому свойству какого объекта значение сейчас присваивается. Выглядеть это в XAML будет кратко и естественно:
Продолжать городить костыли, но заставить XAML вызвать конвертеры:
Вообще-то в WPF встроены средства для локализации, но кому до них дело...
P. S. Код не тестировал, мог наврать.

Как добавить сервисы Google в Android Studio, чтобы уменшить размер

Ребята хочу добавить AdMob, но не используя
compile 'com.google.android.gms:play-services:7.0.0' Так как из за этой команды вес приложение возрастает в 5 раз. До этого весил 700кб, сейчас 5 мегабайт, Это слишком! Есть ли выход? Читал что какой то можно ProGuard задействовать или в Gradle указать чисто для AdMob
Gradle
apply plugin: 'com.android.application'
android { compileSdkVersion 23 buildToolsVersion '23.0.1' defaultConfig { applicationId "com.eranewgames.animevideo" minSdkVersion 10 targetSdkVersion 19 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } productFlavors { } }
repositories{ flatDir{ dirs 'libs' } }
dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile 'com.mcxiaoke.volley:library:1.0.+' compile 'cz.msebera.android:httpclient:4.4.1.1' compile 'com.android.support:appcompat-v7:23.0.1' }


Ответ

Можно подключить отдельно только необходимую часть, полный список тут:
https://developers.google.com/android/guides/setup
Для AdMob достаточно com.google.android.gms:play-services-ads:8.1.0