Подтвердить что ты не робот

Есть ли способ использовать StaticResource в библиотеке управления WPF и иметь возможность просматривать во время разработки?

У меня есть библиотека управления WPF, которая добавляется в приложение форм Windows. Мы хотим, чтобы элементы управления были локализуемыми, однако я не уверен, как ПОЛНОСТЬЮ выполнить это без дублирования кода. Это то, что я делаю сейчас.

В основном, в приложении Windows Form, перед тем как основное приложение запускается, я создаю экземпляр App.xaml, который живет в приложении форм (содержащий мои ссылки на мои ресурсы, которые также живут в приложении форм). Это отлично работает для времени выполнения.

Однако мой пользовательский элемент управления имеет Content="{StaticResource SomeVariableName}", который заканчивается пустым. Я могу исправить это, имея в моей контрольной библиотеке соответствующие словаря app.xaml и соответствующие ресурсные словари, которые соответствуют тем, которые находятся в приложении Windows Forms. Однако это дублированный код.

Вещи, которые я уже пробовал безрезультатно:

  • Создайте экземпляр App.xaml, который живет в библиотеке пользовательского управления из моего приложения форм. Это не работает, потому что URI для моих ресурсов ищет встроенный ресурс, а не мой локальный ресурсный словарь (тогда я мог бы просто скопировать файлы ресурсов из элемента управления в соответствующее место в моем приложении форм в сборке). Могу ли я использовать DeferrableContent здесь? Не так много онлайн, насколько я мог бы найти в этом атрибуте и как его следует использовать, однако.
  • Я хотел бы использовать пост-сборки для приложений и словарей, однако, экземпляр приложения является статической ссылкой на скомпилированный App.xaml, насколько я могу судить. Итак, App.xaml должен жить как минимум в форме
    • Я попытался создать дублированный файл App.xaml с созданием post, перемещающим resourcedictionary.xaml. Я понял, что дублируемое приложение .xaml в порядке, так как это движущая сила, и вы можете не захотеть полагаться на нее из элемента управления (что крутится назад и заставляет вас задаться вопросом, следует ли вам после этого добавить App.xaml в элемент управления все? Если вы не хотите разрешать по умолчанию использование встроенных ресурсов...) Это тоже не показало, что он не смог найти ресурс, даже если он был размещен там, где должен был указывать URI. Декомпилированный код указывает на Uri resourceLocater = new Uri("/WindowsFormsApplication3;component/app.xaml", UriKind.Relative);

Итак, есть ли способ разрешить это работать? И иметь время разработки дизайна по умолчанию по умолчанию и избежать дублирования? Или это дублирование в этом случае? Если мой второй подпункт bullet выглядит нормально (дублируется App.xaml со встроенными скопированными ресурсами), как я могу заставить его не искать элемент уровня компонента, а вместо уровня файла один?

Последний вопрос (и я могу разместить это отдельно, если необходимо), на который я только что обратил внимание. Мой App.xaml встроен в код, так что это не позволяет мне создавать новые ResourceDictionaries на лету в любом случае. Есть ли способ сделать это?

Окончательный вариант... возможно, лучший? - Я все-таки планирую использовать код Андре ван Хеерваарда, так что я должен просто проверить наличие файла и добавить его как объединенный ресурс "на лету" ? В основном, у меня есть один App.xaml в моем элементе управления пользователя, который ссылается на встроенный ResourceDictionary по умолчанию. И затем, если код ищет подходящие локализованные ресурсы "на лету", которые могут быть относительными путями файлов? Единственный недостаток, который я вижу здесь, заключается в том, что по умолчанию нельзя изменить "на лету"... что я, возможно, даже мог бы видеть в определенном месте (используя какое-то соглашение) и предпочитаю ли вы над встроенным?

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

Я могу добавить код, если это поможет вам визуализировать это лучше, просто дайте мне знать.

UPDATE

Теперь у меня возникает проблема с стилем, а не только с локализацией.

Ниже приведен пример одной из внутренних кнопок на одном из элементов управления:

<Button Style="{StaticResource GrayButton}"

Несколько вещей, которые я пробовал/думал:

  • Я не могу создать app.xaml(который никогда не будет использоваться) с ResourceDictionary, установленным как ApplicationDefinitions в библиотечных проектах не допускается. Я мог бы внедрить это в ресурсы управления, но тогда это всегда будет иметь приоритет над любыми ресурсами уровня приложения, и я потеряю возможность настройки.

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

Решение (за пределами верхнего уровня, которое не работает), что я могу думать о том, что это может сработать (и еще нужно попробовать), также кажется большой работой для чего-то, что, по моему мнению, должно быть простым. Но я мог бы создать некоторые свойства зависимостей в элементе управления, с которыми я могу привязать, а затем позволить тем, кто будет переопределен проектом, который будет использовать элемент управления. Как я уже сказал, это похоже на большую работу за довольно простой запрос:). Будет ли это работать? И что еще более важно, есть ли лучшее, более простое решение, которое мне не хватает?

4b9b3361

Ответ 1

Я столкнулся с этой проблемой один раз, и я решил ее, отбросив все "Ресурсы - это объекты, индексированные ключом в канонических словарях".

Я имею в виду, что простой факт определения ресурса в одном проекте и ссылки на него в другом с помощью этого "ключа" должен давать goosebumps любому здравомыслящему человеку. Мне нужны ссылки strong.

Мое решение этой проблемы состояло в том, чтобы создать специальный инструмент, который преобразует мои файлы xaml ресурсов в статические классы с свойством для каждого ресурса:

So MyResources.xaml:

<ResourceDictionary>
  <SolidColorBrush x:Key="LightBrush" ... />
  <SolidColorBrush x:Key="DarkBrush" ... />
</ResourceDictionary>

Становится MyResources.xaml.cs

public static class MyResources {

  static MyResources() {
    // load the xaml file and assign values to static properties
  }

  public static SolidColorBrush LightBrush { get; set; }
  public static SolidColorBrush DarkBrush { get; set; }

}

Для ссылки на ресурс вы можете использовать x:Static вместо StaticResource:

<Border 
   Fill="{x:Static MyResources.LightBrush}"
   BorderBrush="{x:Static MyResources.DarkBrush}"
   ... />

Теперь у вас есть сильные ссылки, автозаполнение и проверка времени компиляции ресурсов.

Ответ 2

У меня тоже возникла проблема с темами стилизации и доступными статическими ресурсами. Итак, я создал автономную библиотеку, в которой в основном не было ничего, кроме тем, которые будут использоваться вложенными, как ваши ресурсы MERGED, связанные с вашим предыдущим связанным вопросом.

Затем в форме Windows (.xaml) я просто поставлю ссылку на эту библиотеку, что-то вроде

<Window x:Class="MyAppNamespace.MyView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" ... />

  <Window.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <!-- Common base theme -->
        <ResourceDictionary   Source="pack://application:,,,/MyLibrary;component/Themes/MyMainThemeWrapper.xaml" />
        </ResourceDictionary.MergedDictionaries>
      </ResourceDictionary>
  </Window.Resources>

  <Rest of XAML for the WPF window>

</Window>

"Компонент", как представляется, относится к корню данного проекта "MyLibrary". В фактическом проекте я создал подпапку под названием "Темы", поэтому источник включает...; component/Themes/...

"MyMainThemeWrapper.xaml" очень похож на ваши вложенные словари с объединенным ресурсом, и он прекрасно видит все остальное из других библиотек.

Ответ 3

Вот мое частное решение вашей проблемы. Я не пытался обрабатывать свободные ресурсы, но у меня есть некоторый успех при совместном использовании ресурсов между WinForms и WPF.

  • Создайте библиотеку классов, чтобы содержать ваши ресурсы в файлах .ResX(например, Resources.resx, Resources.fr.resx и т.д.).
  • Создайте свои элементы управления WPF в пользовательской панели управления WPF
  • Создайте свой WinForms хост
  • Ссылка на ресурсы в вашей библиотеке ресурсов из WPF с помощью Infralution.Localization.Wpf расширения и менеджера культуры, например

    <TextBlock Text="{Resx ResxName=ResourceLib.Resources, Key=Test}"/>
    
  • Поместите содержимое ваших пользовательских элементов управления WPF в один или несколько ресурсных словарей в качестве шаблонов управления, e, g

    <ControlTemplate x:Key="TestTemplate">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
    
            <TextBlock Text="{Resx ResxName=ResourceLib.Resources, Key=Test}"/>
        </Grid>
    </ControlTemplate>
    
  • Используйте шаблон ресурса в пользовательских элементах управления

    <UserControl x:Class="WpfControls.UserControl1"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300" >
        <UserControl.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="ResourceDictionary.xaml"/>
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
        </UserControl.Resources>
        <ContentControl Template="{StaticResource TestTemplate}" />
    </UserControl>
    
  • Добавьте пару строк кода, чтобы все работало

    public partial class UserControl1 : UserControl
    {
        // we require a reference to the resource library to ensure it loaded into memory
        private Class1 _class1 = new Class1();
    
        public UserControl1()
        {
            // Use the CultureManager to switch to the current culture
            CultureManager.UICulture = Thread.CurrentThread.CurrentCulture;
    
            InitializeComponent();
        }
    }
    

Здесь представлено простое демонстрационное приложение под названием WindowsFormsHost.7z