1

次の非常に単純なxamlがあります。

<DocumentViewer Name="dv">
    <FixedDocument Name="fd" Loaded="fd_loaded">
        <FixedDocument.Resources>
            <Style x:Key="TestStyle">
                <Style.Setters>
                    <Setter Property="TextBlock.Foreground" Value="BlueViolet"/>
                </Style.Setters>
            </Style>
            <SolidColorBrush x:Key="foregroundBrush" Color="Orange"/>
        </FixedDocument.Resources>
        <PageContent Name="pc">
            <FixedPage Name="fp" Width="800" Height="600" Name="fp">
                <TextBlock Name="tb" Style="{DynamicResource TestStyle}">
                        Lorem ipsum
                </TextBlock>
                <TextBlock Foreground="{DynamicResource foregroundBrush}" Margin="20">
                        Lorem ipsum
                </TextBlock>
            </FixedPage>
        </PageContent>
    </FixedDocument>
</DocumentViewer>

ここでの動的リソース(より複雑な状況で実際に必要)の使用は機能しません。静的リソースを使用すると、TextBlockが目的の色になります。リソースをFixedPageのレベルに移動することもトリックを行います。ただし、最上位の要素に1つの汎用リソースディクショナリが必要です(ユーザーが色やフォントなどに対して実行可能な変更を行うことができるため)。リソースをアプリケーションレベルに配置することも機能します。しかし、それは正当な理由からの選択肢ではありません。

なぜこれが機能しないのか、誰にも手がかりがあります。TextBlock以降の論理ツリーと関係がありますか?

MSDNリソースの概要には、次のように記載されています。

ルックアッププロセスは、プロパティを設定する要素によって定義されたリソースディクショナリ内で要求されたキーをチェックします。

  • 要素がStyleプロパティを定義している場合、Style内のResourcesディクショナリがチェックされます。
  • 要素がTemplateプロパティを定義している場合、FrameworkTemplate内のResourcesディクショナリがチェックされます。

次に、ルックアッププロセスは、論理ツリーを上方向にトラバースして、親要素とそのリソースディクショナリに到達します。これは、ルート要素に到達するまで続きます。

また、MSDNの上記の説明に従って、ブラシとスタイルを(ダミー)スタイルのリソースに入れてみました。しかし、それもうまくいきませんでした。

これはそれほど複雑なことではないと本当に感じていますが、おそらく私は何かを監督しています。どんな助けでも大歓迎です。

編集

TextBlockに"tb"という名前を付けてから、tb.FindResource( "TestStyle")を使用すると、例外がスローされます。そのため、リソースが明らかに見つかりません。LogicalTreeHelper.GetParent(tb)をチェックアウトし、見つかった親に対してそれを繰り返すと、期待される結果が得られます:TextBlock> FixedPage> PageContent> FixedDocument .. ..

EDIT2

これは完璧に機能します。以前に予測されたXAMLとの違いは何ですか?

<Window x:Class="WpfDynamicStyles2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.Resources>
            <SolidColorBrush x:Key="resBrush" Color="Orange"></SolidColorBrush>
        </Grid.Resources>
            <StackPanel>
            <Button>
                <TextBlock Foreground="{DynamicResource resBrush}">Dummy text...</TextBlock>
            </Button>           
        </StackPanel>
    </Grid>
</Window>

EDIT3

private void fd_Loaded(object sender, RoutedEventArgs e)
{
    Object obj = pc.TryFindResource("foregroundBrush");
    obj = fp.TryFindResource("foregroundBrush");
    obj = tb.TryFindResource("foregroundBrush");
}

テキストボックスのForegroundプロパティに配置された動的リソースは解決できません(実際のリソースはFixedDocument.Resourcesレベルにあります)。また、コードビハインドでTryFindResourceを使用すると、pc(PageContent)からは機能しますが、fp(FixedPage)およびtb(TextBlock)からは、リソースを解決できません(objはnull)。XAMLマークアップで静的リソースを使用すると、すべてが正常に機能します。

4

2 に答える 2

0

スタイルウェイをうまく進めることは良いデザインですが、必須ではありません。ダイナミックカラーベースの同じ名前の(キー付き)ブラシを作成するために、ダイナミックカラーディクショナリ(ブラシディクショナリではない)として使用できます。

解決策は次のようになります...

  1. 単一のブラシリソースディクショナリを作成します。
  2. DynamicResource属性付きのブラシの色を参照してください。
  3. それぞれに同じキー付きカラーリソースを使用して、複数のリソースディクショナリを作成します。
  4. ユーザーの要件に基づいて、クリアしてに追加しApplication.Current.resources.MergedDictionariesます。

  1. 次のXAMLを持つウィンドウでWPFプロジェクトを作成します。

     <Window.Resources>
       <ResourceDictionary>
         <ResourceDictionary.MergedDictionaries>                
            <ResourceDictionary Source="Resources/Window11Resources.xaml"/>
         </ResourceDictionary.MergedDictionaries>
       </ResourceDictionary>
     </Window.Resources>
     <DockPanel LastChildFill="True">
       <ComboBox DockPanel.Dock="Top" VerticalAlignment="Top"
              SelectionChanged="ComboBox_SelectionChanged"
              SelectedIndex="0">
        <ComboBox.ItemsSource>
            <Collections:ArrayList>
                <System:String>Orange</System:String>
                <System:String>Red</System:String>
                <System:String>Blue</System:String>
            </Collections:ArrayList>
        </ComboBox.ItemsSource>
    </ComboBox>
    
    <DocumentViewer>
        <FixedDocument>
            <PageContent>
                <FixedPage Width="793.76" Height="1122.56">
                    <TextBlock
                          FontSize="30"
                          Foreground="{StaticResource LabelColorBrush}"
                          Text="Test"/>
                </FixedPage>
            </PageContent>                
        </FixedDocument>
    </DocumentViewer>        
    

観察する場合、ウィンドウは動的なものを使用する必要はありません。すべての参照は静的なままにすることができます。だからLabelColorBrush辞書で見つけることができますWindow11Resources.xaml

  1. Window11Resources.xaml辞書に動的カラーブラシを追加します。

     <SolidColorBrush x:Key="LabelColorBrush"
                  Color="{DynamicResource DynamicColor}"/>
    
  2. プロジェクトのフォルダに次の3つのカラーブラシ辞書を追加します...

     <!-- Name = OrangeColorResource.xaml -->
     <ResourceDictionary 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
         <Color x:Key="DynamicColor">Orange</Color>
    </ResourceDictionary>
    
     <!-- Name = BlueColorResource.xaml -->
     <ResourceDictionary 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
         <Color x:Key="DynamicColor">Blue</Color>
    </ResourceDictionary>
    
     <!-- Name = RedColorResource.xaml -->
     <ResourceDictionary 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
         <Color x:Key="DynamicColor">Red</Color>
    </ResourceDictionary>
    

キーは同じままであることに注意してくださいDynamicColor

  1. 次に、でカラー辞書をクリアして再作成しApp.Resourcesます。私はの背後にあるコードでそれを行いましたWindow.xaml.cs

    private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        Application.Current.Resources.MergedDictionaries.Clear();
        Application.Current.Resources.MergedDictionaries.Add(
           new ResourceDictionary()
           { 
              Source = new Uri("Resources\\"
                               + ((ComboBox)sender).SelectedItem.ToString()
                               + "ColorResource.xaml",
                               UriKind.RelativeOrAbsolute) });
    }
    

ドロップダウンから色を選択すると、静的リソースブラシで動的な色が変化します。関係するスタイルがないことに注意してください。

これがあなたの求めていることに答えることを願っています。

于 2012-01-02T11:38:57.063 に答える
0

ちなみに、この投稿の理由はもっと複雑な背景がありました。実行時に(エンドユーザーが)色、フォント、フォントサイズなどを動的に変更できる単一のリソースディクショナリを使用したかったのです。納税申告書の申請をしています。また、ユーザー入力用に画面に表示される税務フォームは、アプリケーションレベルでリソースを解決しています。ここまでは順調ですね。

しかし同時に、同じリソースディクショナリ(オブジェクトインスタンスとしてではなくオブジェクトタイプとして)を使用して、印刷に使用する配色、フォント、フォントサイズなどを定義する税務フォームの印刷プレビューをユーザーに提示したいと思います。 。これは、画面上のユーザー入力に使用されるスタイルとは異なる場合があります。そのため、(たとえば)FixedDocumentレベルでリソースディクショナリを「アタッチ」して、ドキュメント内のすべてのページがそれを参照できるようにしました。また、色やフォントなどを変更すると、共通の要素(TextBlocks、TextEditorsなど)を持つすべてのページが変更に応答します。

そして、私は立ち往生しました...この投稿で説明されているように。

今のところ、resourcedictionaryの特定のインスタンスを作成し、それをプライベート変数として保存し、固定ドキュメントに配置するすべての個々のページに添付することで、適切な回避策があります。それは機能し、それはすでに私を喜ばせています。しかし、私のプログラマーの心はまだ少し痛いです。なぜなら、リソースディクショナリの単一のインスタンスを使用し、それをトップレベルのコントロールに配置して、その中のすべてのコントロールがそれを使用できるようにするためです。

プログラマーとして、私たちは回避策にも従わなければなりません;)他に何か提案があれば、私はそれらを受け入れる用意があります。これまでのご支援に感謝します。

グリーツ、ジョープ。

こちらもご覧ください:この問題に関するMSDNフォーラムの投稿

于 2012-01-16T10:04:04.127 に答える