yapa
yapa

Reputation: 171

Use WPF styles like themes

I am now creating an application using WPF. Now I want to change the appearance of the application depend on the user input. Its mean that through a configuration window users can decide how the application looks like and depend on the selection it should change the styles. How can I achieve that rather use several styles per configuration.

For example-

Following rectangle consists of several texts. When restart the application, depend on the user selection it should display the content (changes saved in a some where and it can be easily get the current configuration details and depend on the saved details it should draw the appearance using WPF)

enter image description here

Upvotes: 4

Views: 204

Answers (3)

O. R. Mapper
O. R. Mapper

Reputation: 20770

Place the texts (TextBox) and the image (Image) in a Grid to create the desired layout. The resizing will take place automatically.

Then, bind the Visibility property of each of your texts and your image to a property of some object that stores which state is selected in the options. (The best solution is to store this information in some new class of your own and assign an instance of that class to the DataContext property of your window.

For each of the bindings, create a value converter that returns either Visibility.Visible or Visibility.Collapsed, based on whether the respective element should be visible or invisible with the current options.


EDIT: Here is some exemplary code:

Assuming your very simple settings object looks like this:

public enum GuiMode {
    FourTexts,
    ThreeTexts,
    OneText,
    ThreeTextsAndImage
}

public class GuiSettings : INotifyPropertyChanged
{
    public PropertyChangedEventHandler PropertyChanged;

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

    private GuiMode mode = GuiMode.FourTexts;

    public GuiMode Mode {
        get {
            return mode;
        }
        set {
            if (mode != value) {
                switch (value) {
                    case GuiMode.FourTexts:
                    case GuiMode.ThreeTexts:
                    case GuiMode.OneText:
                    case GuiMode.ThreeTextsAndImage:
                        mode = value;
                        OnPropertyChanged("Mode");
                        break;
                    default:
                        throw new InvalidEnumArgumentException("value", (int)value, typeof(GuiMode));
                }
            }
        }
    }
}

This stores the mode of your GUI. Note the implementation of INotifyPropertyChanged, so when binding to the Mode property, changes of the Mode property will automatically update anything bound to it.

Then, for example, for text2, you could write the following value converter:

public class Text2VisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        switch ((GuiMode)value) {
            case GuiMode.OneText:
                return Visibility.Collapsed;
            default:
                return Visibility.Visible;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException("This converter does not convert back.");
    }
}

As text2 is always visible, except for the state when there is only one text displayed - GuiMode.OneText -, the respective Visibility values are returned by the converter. Also note that this converter simply assumes that the incoming value is a GuiMode value. To do this properly, you should check both what you are getting in value, as well as the targetType.

Once this is done, you can import the converter as a static resource into your Xaml:

<Window.Resources>
    <Text2VisibilityConverter x:Key="text2vis"/>
</Window.Resources>

Depending on which namespaces you have imported, you might need to add the appropriate namespace prefix in front of Text2VisibilityConverter there.

The Visibility property of your text2 can then be bound to the Mode property from the GuiSettings class by using the Text2VisibilityConverter, assuming that the GuiSettings instance where you store your settings has been assigned to the DataContext property of the window:

<TextBlock Text="Text 2" Visibility="{Binding Mode, Converter={StaticResource text2vis}}"/>

Once that works, you can add more value converter classes for the visibilities of the other controls.

Upvotes: 1

Sonhja
Sonhja

Reputation: 8458

You can try something similar to this:

<Grid>
    <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Height="30">
        <Button Content="Option1" Name="Option1" Click="Option1_OnClick"></Button>
        <Button Content="Option2" Name="Option2" Click="Option2_OnClick"></Button>
        <Button Content="Option3" Name="Option3" Click="Option3_OnClick"></Button>
        <Button Content="Full" Name="Full" Click="Full_OnClick"></Button>
    </StackPanel>
    <StackPanel Orientation="Horizontal">
    <Image Source="/WpfApplication3;component/Resources/vaca.png" HorizontalAlignment="Left" VerticalAlignment="Top" Width="150" Height="150" Name="Image"></Image>
        <StackPanel Orientation="Vertical" >
            <Label Content="Text1" Name="Text1" />
            <Label Content="Text2" Name="Text2" />
            <Label Content="Text3" Name="Text3" />
            <Label Content="Text4" Name="Text4" />
        </StackPanel>
    </StackPanel>
</Grid>

Code behind:

 private void Option1_OnClick(object sender, RoutedEventArgs e)
    {
        Image.Visibility = Visibility.Collapsed;
    }

    private void Option2_OnClick(object sender, RoutedEventArgs e)
    {
        Image.Visibility = Visibility.Collapsed;
        Text4.Visibility = Visibility.Collapsed;
    }

    private void Option3_OnClick(object sender, RoutedEventArgs e)
    {
        Image.Visibility = Visibility.Collapsed;
        Text4.Visibility = Visibility.Collapsed;
        Text3.Visibility = Visibility.Collapsed;
        Text2.Visibility = Visibility.Collapsed;
    }

    private void Full_OnClick(object sender, RoutedEventArgs e)
    {
        Image.Visibility = Visibility.Visible;
        Text4.Visibility = Visibility.Visible;
        Text3.Visibility = Visibility.Visible;
        Text2.Visibility = Visibility.Visible;
    }

Upvotes: 0

Matt Ringer
Matt Ringer

Reputation: 1386

The question is pretty general so I'll refer you to a general how on using styles and templates to control how your WPF controls look.

http://msdn.microsoft.com/en-us/magazine/cc163497.aspx

There are several way you can change how your controls look and act at run time.

A direct and easy to understand way(if you've come from winforms) to interact wpf templates is is by overriding the OnApplyTemplate method and then setting the template you want to use from a library of templates you've created or procured.

http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.onapplytemplate.aspx

But what the best approach for you really depends on how you are loading your users preferences and the fundamental design of your UI, MVVM vs MVC vs Custom Controls, etc.

Upvotes: 1

Related Questions