Domanda

Sto cercando di creare un controllo personalizzato, un pulsante, al quale verranno applicati più stili a seconda del valore di una proprietà nel contesto dei dati.

Quello che stavo pensando è usare qualcosa di simile a:

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

E nel codice ... Implementa un IValueConverter che fa qualcosa di simile al codice seguente nel metodo ConvertTo :

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

    ... and so on.
} 

Tuttavia non sono del tutto sicuro di come estrarre l'oggetto di stile e anche se ciò è possibile ...

Quello che sto facendo nel frattempo è gestire l'evento DataContextChanged , quindi collegare un gestore all'evento PropertyChanged dell'oggetto vincolato al pulsante - quindi in esecuzione l'istruzione switch presente.

Non è del tutto perfetto, ma fino a quando non riuscirò a trovare una soluzione migliore sembra che sia quello che dovrò usare.

È stato utile?

Soluzione

Se vuoi sostituire l'intero stile (piuttosto che solo elementi di esso), probabilmente memorizzerai quegli stili nelle risorse. Dovresti essere in grado di fare qualcosa del tipo:

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

Usando un MultiBinding e usando Self come primo binding possiamo quindi cercare le risorse nel nostro convertitore. Il convertitore deve implementare IMultiValueConverter (anziché IValueConverter) e può assomigliare a questo:

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();
    }
}

Non è qualcosa che faccio molto spesso, ma dovrebbe funzionare dalla memoria :)

Altri suggerimenti

Sembra che tu debba usare DataTrigger classe. Ti consente di applicare stili diversi al tuo pulsante in base al suo contenuto.

Ad esempio, il seguente stile cambierà la proprietà di sfondo del pulsante in rosso in base al valore della proprietà dell'oggetto del contesto di dati

<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>

Per quelli di noi che non possono usare il convertitore multi-valore (ti sto guardando SL4 e WP7 :), grazie alla risposta di Steven ho trovato un modo usando un normale convertitore di valore.

L'unico presupposto è che il valore dello stile sia contenuto nella proprietà dello stile impostato.

Quindi, se si utilizza il modello MVVM, si presume che il valore di stile (come TextSmall, TextMedium, TextLarge) faccia parte del modello di visualizzazione e tutto ciò che è necessario fare è passare il parametro del convertitore che definisce il nome di stile.

Ad esempio, supponiamo che il tuo modello di vista abbia proprietà:

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

Stile applicazione:

<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>

Vista XAML:

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

Con la tua classe StyleConverter che implementa IValueConverter:

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;
}

Si noti che questo è il codice WPF, poiché il convertitore deriva da MarkupExtension e IValueConverter, ma funzionerà in SL4 e WP7 se si utilizzano risorse statiche e si aggiunge un po 'più di lavoro alle gambe poiché il metodo TryFindResource non funziona esistere.

Spero che aiuti qualcuno e grazie ancora Steven!

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));
        }
    }

Implementa una proprietà nel tuo ViewModel e poi cambia dinamicamente lo stile ovunque tu voglia come di seguito.

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

Visualizza

Quindi imposta il valore DataContext e quindi implementa il seguente codice nella tua vista

    <Button Style="{Binding DynamicStyle,Mode=TwoWay}"/>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top