среда, 15 июля 2009 г.
MultiVox и Silverlight
В общем после небольшого изучения Silverlight 3, написал сверхпростую смотрелку презентации на сайте АРИС MultiVox. Кода три-четыре функции + асинхронная загрузка списка картинок для просмотра, остальное на себя берет silverlight. В общем впечатления очень приятные.
суббота, 27 июня 2009 г.
Стили и проблема с DataGrid
Чуть с ума не сошел пока не нашел в чем подвох.
Использую DataGrid в своем проекте наблюдал как подвисает вижуал студия в Cider - е.
При этом колонки дата-грида весело улетали вправо на бесконечность (видимо именна эта бесконечность и вешала cider). Оказалось дело в том что на данном окне у меня в ресурсах был прописан стиль для кнопки, в котором устанавливался Margin в 2 или в 3. Вот такой вот сюрприз :)
Использую DataGrid в своем проекте наблюдал как подвисает вижуал студия в Cider - е.
При этом колонки дата-грида весело улетали вправо на бесконечность (видимо именна эта бесконечность и вешала cider). Оказалось дело в том что на данном окне у меня в ресурсах был прописан стиль для кнопки, в котором устанавливался Margin в 2 или в 3. Вот такой вот сюрприз :)
среда, 22 октября 2008 г.
вторник, 21 октября 2008 г.
SelfHostedSilverlight сервис
Часто бывает следующая ситуация, необходимо написать windows службу и специальный конфигуратор к этой службе. Подобные задачи заставляют решать много мелких проблем, например необходимо чтобы служба опрашивала файловую систему или реестр для того чтобы узнать - изменилась ли конфигурация и подобное. С выходом Silverlight мне пришло в голову достаточно удобное решение, которое на мой взгляд является и оптимальным с точки зрения использования и удобным с точки зрения программирования. Представим себе что:
Служба кроме как своей основной деятельности при помощи WCF регистрирует сервис, который в своем контенте содержит все методы для конфигурации службы
Служба внутри себя содержит embedded resource - XAP silverlight файл в котором по сути происходит подсоединению к WCF сервису и вся логика конфигурации
Далее практически с любого компутера где стоит IE/Firefox + Silverlight плагин можно конфигурировать эту службу запросив через Web http XAP у службы.
Как же подобное реализовать. Начнем с самого сложного - WCF части данного проекта:
Silverlght плагин обязан крутиться в рамках политики браузеров - ничего тут не поделаешь, поэтому основное, что требуется от нашей службы - это предоставление правильного crossdomain - документа о доступе к данным службы. Чтобы подобное реализовать нам понадобится:
WebHttpBinding - для доставки подобного контента по запросу браузера
Метод который будет претворяться документом: /clientaccesspolicy.xml
Посмотрим на контракт для сервиса и на наш базовый класс для нашего сервиса:
[ServiceContract]
public interface ISelfHostedPolicy
{
[OperationContract, WebGet(UriTemplate = "/clientaccesspolicy.xml")]
Stream GetSilverlightPolicy();
[OperationContract, WebGet(UriTemplate = "/index.html")]
Stream GetHomePage();
[OperationContract, WebGet(UriTemplate = "/SilverlightPage.xap")]
Stream GetSilverlightPage();
}
Как видим метод GetSilverlightPolicy - должен вернуть текст policy. Метод GetHomePage вернет текст стартовой страницы в которой будет прописан скрипт для загрузки silverlight плагина а сам xap файл вернется в методе GetSilverlightPage. Базовый класс обязан быть совместимым с Asp.Net поэтму на нем висит аттрибут AspNetCompatibilityRequirementsAttribute:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public abstract class SelfHostedConfiguration<T1, T2> : ISelfHostedPolicy where T2 : ISelfHostedPolicy
{
private static byte[] silverlightPage;
private static byte[] homePage;
public static ServiceHost InitServiceHost(string title, Stream silverlightPageStream, Uri baseAddress)
{
if (silverlightPageStream == null)
throw new ArgumentNullException("Silverlight stream is null");
SelfHostedConfiguration<T1, T2>.silverlightPage = StreamToByteArray(silverlightPageStream);
using (var reader = new StreamReader(typeof(ISelfHostedPolicy).Assembly.GetManifestResourceStream("Alda.Framework35.SelfHostedServiceConfig.IndexTemplate.html")))
{
string html = reader.ReadToEnd();
html = html.Replace("$(TITLE)", title);
homePage = StreamToByteArray(new MemoryStream(Encoding.UTF8.GetBytes(html)));
}
ServiceHost host = new ServiceHost(typeof(T2), baseAddress);
host.AddServiceEndpoint(typeof(T1), new BasicHttpBinding(), "basic");
host.AddServiceEndpoint(typeof(ISelfHostedPolicy), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
var smb = new ServiceMetadataBehavior { HttpGetEnabled = true };
host.Description.Behaviors.Add(smb);
return host;
}
private static byte[] StreamToByteArray(Stream stream)
{
using(MemoryStream r = new MemoryStream((int)stream.Length))
{
stream.Seek(0, SeekOrigin.Begin);
while (true)
{
byte[] buff = new byte[32000];
int readed = stream.Read(buff, 0, buff.Length);
r.Write(buff, 0, readed);
if(readed == 0)
break;
}
return r.ToArray();
}
}
#region IPolicyRetriever Members
public Stream GetSilverlightPolicy()
{
string result =
@"<?xml version=""1.0"" encoding=""utf-8""?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers=""*"">
<domain uri=""*""/>
</allow-from>
<grant-to>
<resource path=""/"" include-subpaths=""true""/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>";
WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
return new MemoryStream(Encoding.UTF8.GetBytes(result));
}
public Stream GetHomePage()
{
WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
return new MemoryStream(homePage);
}
public Stream GetSilverlightPage()
{
WebOperationContext.Current.OutgoingResponse.ContentType = "application/x-silverlight";
return new MemoryStream(silverlightPage);
}
#endregion
}
На что здесь необходимо обратить внимание, что InitServiceHost выполняет задачу по регистрации сервиса. Silverlight умеет работать только с BasicHttpBinding - поэтому основной наш сервис ставится в точку с basicHttpBinding. Также важно отметить что наши стартовая страница (index.html) и сам XAP модуль переносятся в byte[] во время инициализации сервиса. Сам IndexTemplate.html добавляется в проект как Embedded Resource и достается во время инициализации сервиса, в нем $(TITLE) заменяется на ваш собственный title. Вот его текст:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<!-- saved from url=(0014)about:internet -->
<head>
<title>$(TITLE)</title>
<style type="text/css">
html, body {
height: 100%;
overflow: auto;
}
body {
padding: 0;
margin: 0;
}
#silverlightControlHost {
height: 100%;
}
</style>
<script type="text/javascript">
function onSilverlightError(sender, args) {
var appSource = "";
if (sender != null && sender != 0) {
appSource = sender.getHost().Source;
}
var errorType = args.ErrorType;
var iErrorCode = args.ErrorCode;
var errMsg = "Unhandled Error in Silverlight 2 Application " + appSource + "\n" ;
errMsg += "Code: "+ iErrorCode + " \n";
errMsg += "Category: " + errorType + " \n";
errMsg += "Message: " + args.ErrorMessage + " \n";
if (errorType == "ParserError")
{
errMsg += "File: " + args.xamlFile + " \n";
errMsg += "Line: " + args.lineNumber + " \n";
errMsg += "Position: " + args.charPosition + " \n";
}
else if (errorType == "RuntimeError")
{
if (args.lineNumber != 0)
{
errMsg += "Line: " + args.lineNumber + " \n";
errMsg += "Position: " + args.charPosition + " \n";
}
errMsg += "MethodName: " + args.methodName + " \n";
}
throw new Error(errMsg);
}
</script>
</head>
<body>
<!-- Runtime errors from Silverlight will be displayed here.
This will contain debugging information and should be removed or hidden when debugging is completed -->
<div id='errorLocation' style="font-size: small;color: Gray;"></div>
<div id="silverlightControlHost">
<object data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%">
<param name="source" value="SilverlightPage.xap"/>
<param name="onerror" value="onSilverlightError" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="2.0.31005.0" />
<param name="autoUpgrade" value="true" />
<a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">
<img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
</a>
</object>
<iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>
</div>
</body>
</html>
как видно стартовая страница будет подгружать SilverlightPage.xap которым у нас притворяется метод GetSilverlightPage.
Двинемся дальше. Создадим тестовый проект (например консольное приложение) который будет у нас нашим сервисом. Добавим ссылки на сборки System.ServiceModel и System.ServiceModel.Web
вот код нашего пробного сервиса:
[ServiceContract]
public interface ILocatorConfig
{
[OperationContract]
string GetVersion();
}
public class LocatorConfig : SelfHostedConfiguration<ILocatorConfig, LocatorConfig>, ILocatorConfig
{
public static void InitConfigService()
{
string baseAddress = "http://" + Environment.MachineName + ":4040";
SelfHostedConfiguration<ILocatorConfig, LocatorConfig>.InitServiceHost("Locator config",
typeof(LocatorConfig).Assembly.GetManifestResourceStream("Alda.LocatorService.Configuration.Alda.LocatorConfig.xap"), new Uri(baseAddress)).Open();
}
public string GetVersion()
{
return "v1.0";
}
}
сам сервис у нас ничего особенно нового не сообщает кроме как версии сервиса. Сам метод main у нас может содержать вызов LocatorConfi.InitConfigService() и например Console.ReadKey();
Так как на настоящий момент мы еще не написали сам Silverlight.XAP модуль для конфигурации вместо typeof(LocatorConfig).Assembly.GetManifestResourceStream("Alda.LocatorService.Configuration.Alda.LocatorConfig.xap") мы передадим пустой new MemoryStream() чтобы InitServiceHost не вылетал с ArgumentNullException. Далее если при запущенном сервисе вы запустите ваш браузер с установленным плагином Silverlight и наберете в нем http://localhost:4040/index.html то должны увидеть пустой экран кликнув правой кнопкой в левый верхний угол которого должны увидеть контекстное меню SilverlightConfiguration.
Теперь пришло время написать наш XAP модуль, здесь мы практически кода писать и не будем - создадим SilverlightApplication проект в Visual Studio 2008 выберем способ хостинга ASP.Net (это нужно только для удобства отладки) и воспользуемся добавлением reference: "Add Service Reference" где в окне самой службы напишем: http://localhost:4040 (важно чтобы в этот момент ваша служба была запущена). Для общения с вашим сервисом вам необходимо будет создать клиента и при помощи асинхронных вызовов общаться со службой - например вот так:
public Page()
{
InitializeComponent();
LocatorConfigClient client = new LocatorConfigClient();
client.OpenCompleted += client_OpenCompleted;
client.OpenAsync();
}
void client_OpenCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
var client = ((LocatorConfigClient) sender);
client.OpenCompleted -= client_OpenCompleted;
client.GetVersionCompleted += client_GetVersionCompleted;
client.GetVersionAsync();
}
void client_GetVersionCompleted(object sender, GetVersionCompletedEventArgs e)
{
var client = ((LocatorConfigClient)sender);
client.GetVersionCompleted -= client_GetVersionCompleted;
client.CloseAsync();
}
Вы можете добавить на вашу страницу настройки все необходимые контроли управления службой и общаться при помощи WCF контрактов с нею. Скомпилированный XAP модуль помещаете в Embedded Resource службы и при вызове метода
SelfHostedConfiguration<ILocatorConfig, LocatorConfig>.InitServiceHost("Locator config",
typeof(LocatorConfig).Assembly.GetManifestResourceStream("Alda.LocatorService.Configuration.Alda.LocatorConfig.xap"), new Uri(baseAddress)).Open(); указываете правильный Stream на ваш XAP модуль.
Важно что базовый адрес не может быть например http://localhost/config - так как clientaccesspolicy.xml обязан лежать на самом верхнем уровне адресов.
Поэтому если у вас нет возможности на самом верхнем уровне прописать clientaccesspolicy.xml то адрессация только при помощи портов.
Служба кроме как своей основной деятельности при помощи WCF регистрирует сервис, который в своем контенте содержит все методы для конфигурации службы
Служба внутри себя содержит embedded resource - XAP silverlight файл в котором по сути происходит подсоединению к WCF сервису и вся логика конфигурации
Далее практически с любого компутера где стоит IE/Firefox + Silverlight плагин можно конфигурировать эту службу запросив через Web http XAP у службы.
Как же подобное реализовать. Начнем с самого сложного - WCF части данного проекта:
Silverlght плагин обязан крутиться в рамках политики браузеров - ничего тут не поделаешь, поэтому основное, что требуется от нашей службы - это предоставление правильного crossdomain - документа о доступе к данным службы. Чтобы подобное реализовать нам понадобится:
WebHttpBinding - для доставки подобного контента по запросу браузера
Метод который будет претворяться документом: /clientaccesspolicy.xml
Посмотрим на контракт для сервиса и на наш базовый класс для нашего сервиса:
[ServiceContract]
public interface ISelfHostedPolicy
{
[OperationContract, WebGet(UriTemplate = "/clientaccesspolicy.xml")]
Stream GetSilverlightPolicy();
[OperationContract, WebGet(UriTemplate = "/index.html")]
Stream GetHomePage();
[OperationContract, WebGet(UriTemplate = "/SilverlightPage.xap")]
Stream GetSilverlightPage();
}
Как видим метод GetSilverlightPolicy - должен вернуть текст policy. Метод GetHomePage вернет текст стартовой страницы в которой будет прописан скрипт для загрузки silverlight плагина а сам xap файл вернется в методе GetSilverlightPage. Базовый класс обязан быть совместимым с Asp.Net поэтму на нем висит аттрибут AspNetCompatibilityRequirementsAttribute:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public abstract class SelfHostedConfiguration<T1, T2> : ISelfHostedPolicy where T2 : ISelfHostedPolicy
{
private static byte[] silverlightPage;
private static byte[] homePage;
public static ServiceHost InitServiceHost(string title, Stream silverlightPageStream, Uri baseAddress)
{
if (silverlightPageStream == null)
throw new ArgumentNullException("Silverlight stream is null");
SelfHostedConfiguration<T1, T2>.silverlightPage = StreamToByteArray(silverlightPageStream);
using (var reader = new StreamReader(typeof(ISelfHostedPolicy).Assembly.GetManifestResourceStream("Alda.Framework35.SelfHostedServiceConfig.IndexTemplate.html")))
{
string html = reader.ReadToEnd();
html = html.Replace("$(TITLE)", title);
homePage = StreamToByteArray(new MemoryStream(Encoding.UTF8.GetBytes(html)));
}
ServiceHost host = new ServiceHost(typeof(T2), baseAddress);
host.AddServiceEndpoint(typeof(T1), new BasicHttpBinding(), "basic");
host.AddServiceEndpoint(typeof(ISelfHostedPolicy), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
var smb = new ServiceMetadataBehavior { HttpGetEnabled = true };
host.Description.Behaviors.Add(smb);
return host;
}
private static byte[] StreamToByteArray(Stream stream)
{
using(MemoryStream r = new MemoryStream((int)stream.Length))
{
stream.Seek(0, SeekOrigin.Begin);
while (true)
{
byte[] buff = new byte[32000];
int readed = stream.Read(buff, 0, buff.Length);
r.Write(buff, 0, readed);
if(readed == 0)
break;
}
return r.ToArray();
}
}
#region IPolicyRetriever Members
public Stream GetSilverlightPolicy()
{
string result =
@"<?xml version=""1.0"" encoding=""utf-8""?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers=""*"">
<domain uri=""*""/>
</allow-from>
<grant-to>
<resource path=""/"" include-subpaths=""true""/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>";
WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
return new MemoryStream(Encoding.UTF8.GetBytes(result));
}
public Stream GetHomePage()
{
WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
return new MemoryStream(homePage);
}
public Stream GetSilverlightPage()
{
WebOperationContext.Current.OutgoingResponse.ContentType = "application/x-silverlight";
return new MemoryStream(silverlightPage);
}
#endregion
}
На что здесь необходимо обратить внимание, что InitServiceHost выполняет задачу по регистрации сервиса. Silverlight умеет работать только с BasicHttpBinding - поэтому основной наш сервис ставится в точку с basicHttpBinding. Также важно отметить что наши стартовая страница (index.html) и сам XAP модуль переносятся в byte[] во время инициализации сервиса. Сам IndexTemplate.html добавляется в проект как Embedded Resource и достается во время инициализации сервиса, в нем $(TITLE) заменяется на ваш собственный title. Вот его текст:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<!-- saved from url=(0014)about:internet -->
<head>
<title>$(TITLE)</title>
<style type="text/css">
html, body {
height: 100%;
overflow: auto;
}
body {
padding: 0;
margin: 0;
}
#silverlightControlHost {
height: 100%;
}
</style>
<script type="text/javascript">
function onSilverlightError(sender, args) {
var appSource = "";
if (sender != null && sender != 0) {
appSource = sender.getHost().Source;
}
var errorType = args.ErrorType;
var iErrorCode = args.ErrorCode;
var errMsg = "Unhandled Error in Silverlight 2 Application " + appSource + "\n" ;
errMsg += "Code: "+ iErrorCode + " \n";
errMsg += "Category: " + errorType + " \n";
errMsg += "Message: " + args.ErrorMessage + " \n";
if (errorType == "ParserError")
{
errMsg += "File: " + args.xamlFile + " \n";
errMsg += "Line: " + args.lineNumber + " \n";
errMsg += "Position: " + args.charPosition + " \n";
}
else if (errorType == "RuntimeError")
{
if (args.lineNumber != 0)
{
errMsg += "Line: " + args.lineNumber + " \n";
errMsg += "Position: " + args.charPosition + " \n";
}
errMsg += "MethodName: " + args.methodName + " \n";
}
throw new Error(errMsg);
}
</script>
</head>
<body>
<!-- Runtime errors from Silverlight will be displayed here.
This will contain debugging information and should be removed or hidden when debugging is completed -->
<div id='errorLocation' style="font-size: small;color: Gray;"></div>
<div id="silverlightControlHost">
<object data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%">
<param name="source" value="SilverlightPage.xap"/>
<param name="onerror" value="onSilverlightError" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="2.0.31005.0" />
<param name="autoUpgrade" value="true" />
<a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">
<img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
</a>
</object>
<iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>
</div>
</body>
</html>
как видно стартовая страница будет подгружать SilverlightPage.xap которым у нас притворяется метод GetSilverlightPage.
Двинемся дальше. Создадим тестовый проект (например консольное приложение) который будет у нас нашим сервисом. Добавим ссылки на сборки System.ServiceModel и System.ServiceModel.Web
вот код нашего пробного сервиса:
[ServiceContract]
public interface ILocatorConfig
{
[OperationContract]
string GetVersion();
}
public class LocatorConfig : SelfHostedConfiguration<ILocatorConfig, LocatorConfig>, ILocatorConfig
{
public static void InitConfigService()
{
string baseAddress = "http://" + Environment.MachineName + ":4040";
SelfHostedConfiguration<ILocatorConfig, LocatorConfig>.InitServiceHost("Locator config",
typeof(LocatorConfig).Assembly.GetManifestResourceStream("Alda.LocatorService.Configuration.Alda.LocatorConfig.xap"), new Uri(baseAddress)).Open();
}
public string GetVersion()
{
return "v1.0";
}
}
сам сервис у нас ничего особенно нового не сообщает кроме как версии сервиса. Сам метод main у нас может содержать вызов LocatorConfi.InitConfigService() и например Console.ReadKey();
Так как на настоящий момент мы еще не написали сам Silverlight.XAP модуль для конфигурации вместо typeof(LocatorConfig).Assembly.GetManifestResourceStream("Alda.LocatorService.Configuration.Alda.LocatorConfig.xap") мы передадим пустой new MemoryStream() чтобы InitServiceHost не вылетал с ArgumentNullException. Далее если при запущенном сервисе вы запустите ваш браузер с установленным плагином Silverlight и наберете в нем http://localhost:4040/index.html то должны увидеть пустой экран кликнув правой кнопкой в левый верхний угол которого должны увидеть контекстное меню SilverlightConfiguration.
Теперь пришло время написать наш XAP модуль, здесь мы практически кода писать и не будем - создадим SilverlightApplication проект в Visual Studio 2008 выберем способ хостинга ASP.Net (это нужно только для удобства отладки) и воспользуемся добавлением reference: "Add Service Reference" где в окне самой службы напишем: http://localhost:4040 (важно чтобы в этот момент ваша служба была запущена). Для общения с вашим сервисом вам необходимо будет создать клиента и при помощи асинхронных вызовов общаться со службой - например вот так:
public Page()
{
InitializeComponent();
LocatorConfigClient client = new LocatorConfigClient();
client.OpenCompleted += client_OpenCompleted;
client.OpenAsync();
}
void client_OpenCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
var client = ((LocatorConfigClient) sender);
client.OpenCompleted -= client_OpenCompleted;
client.GetVersionCompleted += client_GetVersionCompleted;
client.GetVersionAsync();
}
void client_GetVersionCompleted(object sender, GetVersionCompletedEventArgs e)
{
var client = ((LocatorConfigClient)sender);
client.GetVersionCompleted -= client_GetVersionCompleted;
client.CloseAsync();
}
Вы можете добавить на вашу страницу настройки все необходимые контроли управления службой и общаться при помощи WCF контрактов с нею. Скомпилированный XAP модуль помещаете в Embedded Resource службы и при вызове метода
SelfHostedConfiguration<ILocatorConfig, LocatorConfig>.InitServiceHost("Locator config",
typeof(LocatorConfig).Assembly.GetManifestResourceStream("Alda.LocatorService.Configuration.Alda.LocatorConfig.xap"), new Uri(baseAddress)).Open(); указываете правильный Stream на ваш XAP модуль.
Важно что базовый адрес не может быть например http://localhost/config - так как clientaccesspolicy.xml обязан лежать на самом верхнем уровне адресов.
Поэтому если у вас нет возможности на самом верхнем уровне прописать clientaccesspolicy.xml то адрессация только при помощи портов.
вторник, 29 апреля 2008 г.
Сборки со строгим именем
В случае когда необходимо загрузить ResourceDictionary из другой сборки часто приходится писать что-то вроде такого:
Source="/Alda.WPF;component/CommonConverters.xaml"
однако могут возникнуть проблемы в случае, когда сборка имеет строгое имя. Тогда необходимо указывать версию и public key token
Source="/Alda.WPF;V1.0.0.0;0e2fb8bcf6bca8e4;component/CommonConverters.xaml"
Source="/Alda.WPF;component/CommonConverters.xaml"
однако могут возникнуть проблемы в случае, когда сборка имеет строгое имя. Тогда необходимо указывать версию и public key token
Source="/Alda.WPF;V1.0.0.0;0e2fb8bcf6bca8e4;component/CommonConverters.xaml"
понедельник, 28 апреля 2008 г.
CustomWPF library
У меня долгое время вылетали непонятные ошибки типа XamlParseException или невозможности загрузить ResourceDictionary из сборки в случае когда одна сборка ссылается на другую и использует UserControl из другого namespace.
проблема решилась когда в аттрибутах сборки с UserControl - ем был добавлен следующий аттрибут:
[assembly: XmlnsDefinition(
"http://multivox.ru/MyAssembly.dll",
"MyNamespace")].
С таким объявлением аттрибута у сборки проблемы вроде как исчезли.
проблема решилась когда в аттрибутах сборки с UserControl - ем был добавлен следующий аттрибут:
[assembly: XmlnsDefinition(
"http://multivox.ru/MyAssembly.dll",
"MyNamespace")].
С таким объявлением аттрибута у сборки проблемы вроде как исчезли.
Ярлыки:
assembly,
ResourceDictionary,
WPF,
xamlparseexception
я не активный блоггер
Добрый день, я не активный блоггер, но, иногда, у меня получается решить некоторые
проблемы связанные с WPF. Так что может кому будет полезным.
проблемы связанные с WPF. Так что может кому будет полезным.
Подписаться на:
Сообщения (Atom)