web-dev-qa-db-ja.com

WPFコントロールライブラリでStaticResourceを使用し、設計時に表示できる方法はありますか?

Windowsフォームアプリケーションに追加されているWPFコントロールライブラリがあります。コントロールをローカライズできるようにしたいのですが、コードを複製せずにこれを完全に実現する方法がわかりません。 これは私が今していることです

基本的に、Windowsフォームアプリでは、メインアプリケーションが起動する前に、フォームアプリ内にあるApp.xamlをインスタンス化しています(フォームアプリ内にもあるリソースへのリンクが含まれています)。これは実行時に完全に機能します。

ただし、私のユーザーコントロールにはすべて_Content="{StaticResource SomeVariableName}"_があり、空白になってしまいます。これを修正するには、app.xamlと、Windowsフォームアプリのものと一致する適切なリソース辞書をコントロールライブラリに配置します。ただし、これは重複したコードです。

私がすでに役に立たなかったこと:

  • フォームアプリ内からユーザーコントロールライブラリ内にあるApp.xamlをインスタンス化します。リソースへのURIがローカルリソースディクショナリではなく埋め込みリソースを探しているため、これは機能しません(その後、ビルド時にコントロールからフォームアプリ内の適切な場所にリソースファイルをコピーするだけで済みます)。ここで DeferrableContent を活用できますか?ただし、この属性とその使用方法について私が知る限り、オンラインはあまりありません。
  • アプリと辞書の両方にポストビルドを使用したいのですが、アプリのインスタンス化は、私が知る限り、コンパイルされたApp.xamlへの静的参照です。したがって、App.xamlは少なくとものフォーム内に存在する必要があります。
    • Resourcedictionary.xamlを移動するポストビルドを使用して、複製されたApp.xamlを作成しようとしました。複製されたapp.xamlはそれが原動力であり、とにかくコントロールからのものに依存したくないかもしれないので大丈夫だと思いました(これは円を描き、App.xamlをコントロールに含めるべきかどうか疑問に思います埋め込みリソースを使用するデフォルトを許可したい場合を除いて...)URIが指すはずの場所に配置されていても、リソースが見つからないと言って失敗しました。逆コンパイルされたコードはUri resourceLocater = new Uri("/WindowsFormsApplication3;component/app.xaml", UriKind.Relative);を指します

それで、これを機能させ、コンポーネントのデフォルトを設計時に表示し、重複を回避する方法はありますか?または、この場合の複製は問題ありませんか? 2番目の箇条書きのサブアイテムに問題がないように見える場合(ビルドコピーされたリソース辞書を使用してApp.xamlを複製)、コンポーネントレベルのアイテムではなく、ファイルレベルのアイテムを検索するようにするにはどうすればよいですか?

私が注意を払った最後の質問(そして必要に応じてこれを個別に投稿できます)。私のApp.xamlはコードに組み込まれているため、とにかくその場で新しいResourceDictionariesを作成することはできません。これを行う方法はありますか?

最後のオプション...おそらく最良のオプション?とにかくAndre van Heerwaardeのコードを使用する予定です ファイルの存在を確認し、その場でマージされたリソースとして追加しますか?基本的に、デフォルトの埋め込みResourceDictionaryにリンクする1つのApp.xamlをユーザーコントロールに配置します。そして、コードにその場で適切なローカライズされたリソースを探しさせますか?それは相対的なファイルパスである可能性がありますか?ここで私が見る唯一の欠点は、デフォルトをその場で変更できないことです...おそらく、指定された場所で(ある種の規則を使用して)その外観を持ち、組み込みのものよりも優先される可能性がありますか?

ああ、埋め込みリソースが必要ない理由は、ビルドのデプロイ後にエンドユーザーが新しいローカライズされたリソースを追加/変更できるようにするためです。

これをよりよく視覚化するのに役立つ場合は、コードを追加できます。お知らせください。

[〜#〜]更新[〜#〜]

私は今、ローカライズだけでなく、スタイリングに関するさらなる問題に直面しています。

コントロールの1つにある内部ボタンの1つの例を次に示します。

_<Button Style="{StaticResource GrayButton}"
_

私が試した/考えた他のいくつかのこと:

  • ライブラリプロジェクトではApplicationDefinitionsが許可されていないため、ResourceDictionaryを設定してapp.xaml(使用されることはありません)を作成できません。これをコントロールのリソースに埋め込むことはできますが、それは常にアプリケーションレベルのリソースよりも優先され、カスタマイズ性が失われます。

これが接続ケースです これは実際に私が探しているもののように聞こえますが、これに対する実際の解決策は提供されていません

私が考えることができる(そしてまだ試していない)解決策(トップを超えて..それは機能しません)も、私が単純であるべきだと思う何かのための多くの作業のようです。ただし、バインドできるいくつかの依存関係プロパティをコントロールに作成し、それらをコントロールを使用するプロジェクトでオーバーライドできるようにすることができる場合があります。私が言ったように、それは非常に単純な要求のために多くの仕事のように思えます:)。これでもうまくいくでしょうか?そしてもっと重要なことに、私が見逃しているより良い、より単純な解決策はありますか?

24
Justin Pihony

私は一度この問題に遭遇しましたが、「リソースは正規辞書のキーによってインデックス付けされたオブジェクトです」というもの全体を削除することで解決しました。

つまり、あるプロジェクトでリソースを定義し、その「キー」によって別のプロジェクトでリソースを参照するという単純な事実は、正気の人に鳥肌を与えるはずです。 強い参照が欲しかった。

この問題に対する私の解決策は、リソースxamlファイルを各リソースのプロパティを持つ静的クラスに変換する カスタムツール を作成することでした。

したがって、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; }

}

リソースを参照するには、StaticResourceの代わりにx:Staticを使用できます。

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

これで、リソースの強力な参照、オートコンプリート、コンパイル時のチェックが可能になりました。

15

私もスタイリングテーマと利用可能な静的リソースの処理に問題がありました。そこで、以前のリンクされた質問の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」プロジェクトのルートを参照しているように見えます。実際のプロジェクトでは、「Themes」というサブフォルダーを作成したため、ソースには...; component/Themes/..が含まれています。

「MyMainThemeWrapper.xaml」は、ネストされたマージリソースディクショナリに非常によく似ており、他のライブラリからすべてを完全に認識します。

0
DRapp

これがあなたの問題に対する私のpartial解決策です。緩いリソースを処理しようとはしていませんが、WinFormsとWPFの間でリソースを共有することである程度の成功を収めています。

  • .ResXファイル(Resources.resx、Resources.fr.resxなど)にリソースを含めるクラスライブラリを作成します
  • WPFユーザーコントロールライブラリにWPFコントロールを作成する
  • WinFormsホストを作成します
  • Infralution.Localization.Wpf マークアップ拡張機能とカルチャマネージャーを使用して、WPFからリソースライブラリ内のリソースを参照します。

    <TextBlock Text="{Resx ResxName=ResourceLib.Resources, Key=Test}"/>
    
  • WPFユーザーコントロールのコンテンツを、コントロールテンプレートとして1つ以上のリソースディクショナリに配置します。

    <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's 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と呼ばれるものです

0
Phil