none
UserControl 内部のコントロールのスタイルを設定する RRS feed

  • 質問

  • UserControl 内部のコントロールのスタイルを外部から設定することはできますでしょうか。
    利用側ウィンドウの XAML に下記を記述しても動作しませんでした。

            <local:ProjectButtonBand Height="Auto" ButtonCount="2" IsTabStop="False" Grid.Row="1">
                <local:ProjectButtonBand.Resources>
                    <Style TargetType="Button">
                        <Setter Property="Width" Value="10"></Setter>
                        <Setter Property="Margin" Value="2,1"></Setter>
                    </Style>
                </local:ProjectButtonBand.Resources>
                <!--<local:ProjectButtonBand.ButtonStyle>
                    <Style TargetType="Button">
                        <Setter Property="Width" Value="60"></Setter>
                        <Setter Property="Margin" Value="2,1"></Setter>
                    </Style>                
                </local:ProjectButtonBand.ButtonStyle>-->
            </local:ProjectButtonBand>

    上記でコメントアウトしていますが、依存関係プロパティ ButtonStyle を作成して、スタイルを上書きするプログラムを書けば適用されました。このような対応が個別に必要になるのか wpf の機能として利用できるものがないか知りたいと考えております。

    以下追記、4/19 23:45 ころ
    説明が不足していましたので補足致します。ご迷惑をおかけします。
    UserControl には複数のボタンを配置しています。
    UserControl を使う場所によってはボタンサイズを変えたり、マージンを変えたりしたいです。
    そしてスタイルの既定値も与えたいと思います。
    但し、1つの UserControl 内のボタンのスタイルは同じにします。
    ボタンに表示するテキストやコマンドそのものはボタン毎に異なりますが今回の質問の対象外です。

    UserControl の名前は ProjectButtonBand としており、下記のような xaml になっています。

    <UserControl x:Class="WpfApplication1.ProjectButtonBand"
                 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" 
                 xmlns:local="clr-namespace:WpfApplication1"
                 mc:Ignorable="d" d:DesignWidth="300" Height="Auto">
        <WrapPanel Margin="0,0,0,0" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
            <!--<WrapPanel.Resources>
                <Style TargetType="Button">
                    <Setter Property="Width" Value="100"/>
                    <Setter Property="Height" Value="32"/>
                    <Setter Property="Margin" Value="4,4"/>
                    <Setter Property="VerticalAlignment" Value="Center"/>
                </Style>
            </WrapPanel.Resources>-->
            <Button Name="Button1"/>
            <Button Name="Button0"/>
        </WrapPanel>
    </UserControl>
    

    コードビハインドは InitializeComponent(); を呼び出すコンストラクターがあるだけにしてみました。
    この状態で利用側 xaml に前述の通り記述しても利用側で指定したスタイルは無視されているように見えました。
    このような状況です。


    http://systemartlaboratory.com/


    • 編集済み 三輪の牛 2017年4月29日 14:45 説明不足のため
    2017年4月28日 5:19

回答

  • ボタンだけ配置したUserControlを作成して試したところ、問題なく適用されました。

    UserControlでResourcesを定義していると再初期化できない例外が発生するようです。
    もしこの症状に該当しUserControlを編集できるのならば、UserControlで定義しているResourcesをひとつ下の階層に持たせる方法はいかがでしょか。

    <UserControl ...>
        <Grid>
            <Grid.Resources>
                ...
            </Grid.Resources>
            <Button Content="Hello!"/>
        </Grid>
    </UserControl>

    • 回答としてマーク 三輪の牛 2017年5月2日 14:48
    2017年4月29日 12:34
  • 下記 URL を参考に MergedDictionaries を使うとうまく動作しました。

    http://stackoverflow.com/questions/33658491/how-do-i-set-resources-in-xaml-on-a-wpf-component-that-already-has-resources

    UserControl 側の XAML は下記の通りになりました。

    <UserControl x:Class="WpfApplication1.ProjectButtonBand"
                 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" 
                 xmlns:local="clr-namespace:WpfApplication1"
                 mc:Ignorable="d" d:DesignWidth="300" Height="Auto">
        <UserControl.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary>
                        <Style TargetType="Button">
                            <Setter Property="Width" Value="100"/>
                            <Setter Property="Height" Value="32"/>
                            <Setter Property="Margin" Value="4,4"/>
                            <Setter Property="VerticalAlignment" Value="Center"/>
                        </Style>
                    </ResourceDictionary>
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
        </UserControl.Resources>
        <WrapPanel Margin="0,0,0,0" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button Name="Button1"/>
            <Button Name="Button0"/>
        </WrapPanel>
    </UserControl>

    Resources というプロパティをシャドウしていますが、ButtonStyle というプロパティを設けるよりは一般性がありますので、この方法が良さそうな気がしてきました。


    http://systemartlaboratory.com/



    • 編集済み 三輪の牛 2017年5月1日 13:46 リンク有効化
    • 回答としてマーク 三輪の牛 2017年5月2日 14:48
    2017年5月1日 13:45

すべての返信

  • どのようなことがされたいのかはっきりわからないので外しているかもしれませんが、例えば条件によってStyleを変更したいのであれば、Sytleへのバインドを使い、Converterで変更するという方法があります。

    (参考)
    Use a StyleSelector for a button
    http://stackoverflow.com/questions/5082509/use-a-styleselector-for-a-button


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    2017年4月28日 9:09
    モデレータ
  • UserControlをホストするPanel(Gridなど)を一段かませて、そのPanelのResourcesでStyleを定義してみてはどうですか?
    2017年4月28日 17:55
  • ボタンだけ配置したUserControlを作成して試したところ、問題なく適用されました。

    UserControlでResourcesを定義していると再初期化できない例外が発生するようです。
    もしこの症状に該当しUserControlを編集できるのならば、UserControlで定義しているResourcesをひとつ下の階層に持たせる方法はいかがでしょか。

    <UserControl ...>
        <Grid>
            <Grid.Resources>
                ...
            </Grid.Resources>
            <Button Content="Hello!"/>
        </Grid>
    </UserControl>

    • 回答としてマーク 三輪の牛 2017年5月2日 14:48
    2017年4月29日 12:34
  • trapemiya さん、sygh さん、neelabo さんありがとうございます。

    sygh さん、neelabo さんの回答の意味がようやくわかりました。
    下記のように ControlTemplate を使いますと、完全ではありませんがデザイン時は動作しておりました。
    しかし、ご指摘の通り2回 Resources を初期化することになって実行時に例外が発生しました。

    <UserControl x:Class="WpfApplication1.ProjectButtonBand"
                 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" 
                 xmlns:local="clr-namespace:WpfApplication1"
                 mc:Ignorable="d" d:DesignWidth="300" Height="Auto">
        <UserControl.Resources>
            <Style TargetType="Button">
                <Setter Property="Width" Value="100"/>
                <Setter Property="Height" Value="32"/>
                <Setter Property="Margin" Value="4,4"/>
                <Setter Property="VerticalAlignment" Value="Center"/>
            </Style>
        </UserControl.Resources>
        <UserControl.Template>
            <ControlTemplate TargetType="UserControl">
                <WrapPanel Margin="0,0,0,0" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
                    <Button Name="Button1"/>
                    <Button Name="Button0"/>
                </WrapPanel>
            </ControlTemplate>
        </UserControl.Template>
    </UserControl>
    なので、Resources を設定する要素を変更して回避すると理解しました。
    やってみますとより内側の要素で設定した Resources が優先となるようで、外側で設定したスタイルは無視されました。


    http://systemartlaboratory.com/


    2017年5月1日 6:43
  • 下記 URL を参考に MergedDictionaries を使うとうまく動作しました。

    http://stackoverflow.com/questions/33658491/how-do-i-set-resources-in-xaml-on-a-wpf-component-that-already-has-resources

    UserControl 側の XAML は下記の通りになりました。

    <UserControl x:Class="WpfApplication1.ProjectButtonBand"
                 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" 
                 xmlns:local="clr-namespace:WpfApplication1"
                 mc:Ignorable="d" d:DesignWidth="300" Height="Auto">
        <UserControl.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary>
                        <Style TargetType="Button">
                            <Setter Property="Width" Value="100"/>
                            <Setter Property="Height" Value="32"/>
                            <Setter Property="Margin" Value="4,4"/>
                            <Setter Property="VerticalAlignment" Value="Center"/>
                        </Style>
                    </ResourceDictionary>
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
        </UserControl.Resources>
        <WrapPanel Margin="0,0,0,0" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button Name="Button1"/>
            <Button Name="Button0"/>
        </WrapPanel>
    </UserControl>

    Resources というプロパティをシャドウしていますが、ButtonStyle というプロパティを設けるよりは一般性がありますので、この方法が良さそうな気がしてきました。


    http://systemartlaboratory.com/



    • 編集済み 三輪の牛 2017年5月1日 13:46 リンク有効化
    • 回答としてマーク 三輪の牛 2017年5月2日 14:48
    2017年5月1日 13:45