web-dev-qa-db-ja.com

WPFスタイルのバインド

カスタムコントロール(ボタン)を作成しようとしています。ボタンには、データコンテキスト内のプロパティの値に応じて複数のスタイルが適用されます。

私が考えていたのは、次のようなものを使用しています:

<Button Style="{Binding Path=ButtonStyleProperty, Converter={StaticResource styleConverter}}" Text="{Binding Path=TextProp}" />

そしてコードで... ConvertToメソッドで以下のコードと同様のことを行うIValueConverterを実装します。

switch(value as ValueEnums)
{
    case ValueEnums.Enum1:
        FindResource("Enum1ButtonStyle") as Style;
    break;

    ... and so on.
} 

しかし、私はスタイルオブジェクトをどのように引き出すかについて完全に確信がありませんし、これがまったく可能であるとしても...

その間に私がしていることは、DataContextChangedイベントを処理してから、ボタンにバインドされているオブジェクトのPropertyChangedイベントにハンドラーをアタッチし、そこでswitchステートメントを実行することです。

完璧ではありませんが、より良い解決策が見つかるまでは、それを使用する必要があるようです。

34
Matthew Savage

(要素だけではなく)スタイル全体を置き換える場合は、おそらくそれらのスタイルをリソースに格納します。次のように何かを実行できるはずです。

<Button>
    <Button.Style>
        <MultiBinding Converter="{StaticResource StyleConverter}">
            <MultiBinding.Bindings>
                <Binding RelativeSource="{RelativeSource Self}"/>
                <Binding Path="MyStyleString"/>
            </MultiBinding.Bindings>
        </MultiBinding>
    </Button.Style>
</Button>

MultiBindingを使用し、最初のバインディングとしてSelfを使用することで、コンバーターでリソースを検索できます。コンバーターは(IValueConverterではなく)IMultiValueConverterを実装する必要があり、次のようになります。

class StyleConverter : IMultiValueConverter 
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        FrameworkElement targetElement = values[0] as FrameworkElement; 
        string styleName = values[1] as string;

        if (styleName == null)
            return null;

        Style newStyle = (Style)targetElement.TryFindResource(styleName);

        if (newStyle == null)
            newStyle = (Style)targetElement.TryFindResource("MyDefaultStyleName");

        return newStyle;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

それは私が頻繁に行うことではありませんが、それはメモリから機能するはずです:)

38
Steven Robbins

DataTrigger クラスを使用する必要があるようです。それはあなたがそれの内容に基づいてあなたのボタンに異なるスタイルを適用することを可能にします。

たとえば、次のスタイルは、データコンテキストオブジェクトのプロパティの値に基づいてボタンの背景プロパティを赤に変更します

<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding Path="Some property"}" 
                     Value="some property value">
            <Setter Property="Background" Value="Red"/>
        </DataTrigger>
    </Style.Triggers>
</Style>
15
aku

マルチバリューコンバーターを使用できない私たち(SL4とWP7を見てます)のために、スティーブンの回答のおかげで、通常のバリューコンバーターを使用する方法を見つけました。

唯一の前提は、スタイル値が、設定されるスタイルのプロパティ内に含まれていることです。

したがって、MVVMパターンを使用している場合、スタイル値(TextSmall、TextMedium、TextLargeなど)はビューモデルの一部と見なされ、スタイル名を定義するコンバーターパラメーターを渡すだけで済みます。

たとえば、ビューモデルに次のプロパティがあるとします。

public string ProjectNameStyle
{
    get { return string.Format("ProjectNameStyle{0}", _displaySize.ToString()); }
}

アプリケーションスタイル:

<Application.Resources>
    <Style x:Key="ProjectNameStyleSmall" TargetType="TextBlock">
        <Setter Property="FontSize" Value="40" />
    </Style>
    <Style x:Key="ProjectNameStyleMedium" TargetType="TextBlock">
        <Setter Property="FontSize" Value="64" />
    </Style>
    <Style x:Key="ProjectNameStyleLarge" TargetType="TextBlock">
        <Setter Property="FontSize" Value="90" />
    </Style>

XAMLビュー:

   <TextBlock 
        Text="{Binding Name}"
        Style="{Binding ., Mode=OneWay, Converter={cv:StyleConverter}, ConverterParameter=ProjectNameStyle}">

IValueConverterを実装するStyleConverterクラスで:

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    if (targetType != typeof(Style))
    {
        throw new InvalidOperationException("The target must be a Style");
    }

    var styleProperty = parameter as string;
    if (value == null || styleProperty == null)
    {
        return null;
    }

    string styleValue = value.GetType()
        .GetProperty(styleProperty)
        .GetValue(value, null)
        .ToString();
    if (styleValue == null)
    {
        return null;
    }

    Style newStyle = (Style)Application.Current.TryFindResource(styleValue);
    return newStyle;
}

コンバーターはMarkupExtensionとIValueConverterから派生しているため、これはWPFコードであることに注意してください。ただし、静的リソースを使用し、TryFindResourceメソッドが存在しないため、レッグ作業を追加すると、SL4およびWP7で機能します。

それが誰かを助けることを願って、そして再びスティーブンに感謝します!

8
si618

ViewModel

private Style _dynamicStyle = (Style)Application.Current.FindResource("Style1");
        public Style DynamicStyle
        {
            get { return _dynamicStyle; }
            set
            {
                _dynamicStyle = value;
                OnPropertyChanged("DynamicStyle");
            }

        }

public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

ViewModelにプロパティを実装し、以下のようにスタイルを動的に変更します。

DynamicStyle=(Style)Application.Current.FindResource("Style2");// you can place this code where the action get fired

ビュー

次にDataContext値を設定し、ビューに次のコードを実装します

    <Button Style="{Binding DynamicStyle,Mode=TwoWay}"/>
1
Chandru A