使用 WPF 样式,如主题。

4
我现在正在使用WPF创建一个应用程序。我想根据用户输入更改应用程序的外观。这意味着用户可以通过配置窗口决定应用程序的外观,并根据选择更改样式。如何实现此目标而不是使用多个样式来完成配置?
例如,下面的矩形由几个文本组成。当重新启动应用程序时,根据用户的选择,它应该显示相应的内容(更改保存在某个地方,可以轻松获取当前的配置详细信息,并根据保存的详细信息使用WPF绘制外观):
- 如果用户选择显示所有4个文本,则应像第一张图片那样显示; - 如果用户选择仅显示3个或2个文本,则应根据文本内容重新调整矩形的大小(如图3/4); - 例如,如果此矩形包含图像,则应相应调整矩形的大小。如果用户更改设置以从矩形中删除图片,则应将其删除并相应调整矩形的大小(如图4)。

Window.SizeToContent 设置为 WidthAndHeight?:http://msdn.microsoft.com/en-us/library/system.windows.window.sizetocontent.aspx - Bolu
似乎你需要从DynamicResources中获取并根据所选内容编程性地更改其值。首先,你是否熟悉面板的“模板”选项?如果是的话,你可以在ResourceDictionary中创建4种不同的Styles,每种都具有不同的模板(每一种都与你的设计相适应),并进行编程性更改。 - Sonhja
@Bolu 这并不完全符合他的需求。他需要更改内容,而不仅仅是定位。这就是样式(在这种情况下管理“模板”内容)。 - Sonhja
@Sonhja,但他需要Window随内容一起调整大小吗? - Bolu
3个回答

1

将文本(TextBox)和图片(Image)放入Grid中,创建所需的布局。自动调整大小。

然后,将每个文本和图像的Visibility property绑定到某个对象的属性上,该对象存储选项中选择的状态。(最好的解决方案是在您自己的新类中存储此信息,并将该类的实例分配给窗口的DataContext property。)

对于每个绑定,创建一个值转换器,根据当前选项返回Visibility.VisibleVisibility.Collapsed,以确定相应元素是否可见。请保留HTML标签。

编辑:这里有一些示例代码:

假设您的非常简单的设置对象如下所示:

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

这个存储你GUI的模式。请注意INotifyPropertyChanged的实现,因此当绑定到Mode属性时,Mode属性的更改将自动更新任何绑定到它的内容。
然后,例如,对于text2,您可以编写以下值转换器:
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.");
    }
}

作为文本2始终可见,除了只显示一个文本的状态- GuiMode.OneText - 转换器返回相应的Visibility值。另请注意,该转换器仅假定传入的value是GuiMode值。为了正确处理,您应该检查value和targetType。完成后,您可以将转换器作为静态资源导入到Xaml中:
<Window.Resources>
    <Text2VisibilityConverter x:Key="text2vis"/>
</Window.Resources>

根据您导入的命名空间,您可能需要在那里添加适当的命名空间前缀,以便正确使用Text2VisibilityConverter
然后,可以使用Text2VisibilityConvertertext2Visibility属性绑定到GuiSettings类的Mode属性,假设存储设置的GuiSettings实例已分配给窗口的DataContext属性
<TextBlock Text="Text 2" Visibility="{Binding Mode, Converter={StaticResource text2vis}}"/>

一旦这个工作完成,您可以为其他控件的可见性添加更多的值转换器类。

这是一种非常简单和容易的方法! :) 只需要使用 switch case,就不需要样式。 - Sonhja
好的。您能否给我一些示例代码(仅限如何使用值转换器)? - yapa
@yapa:我已经添加了一个示例和一些解释;如果有任何提示缺失,请告诉我。 - O. R. Mapper
我会检查的。非常感谢。 - yapa

1

这个问题比较泛,因此我会向您介绍一些关于如何使用样式和模板来控制WPF控件外观的基本方法。

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

有几种方法可以在运行时更改控件的外观和行为。

如果您是从WinForms转换而来,与WPF模板进行交互的一种直接易懂的方法是通过覆盖OnApplyTemplate方法,然后从您创建或采购的模板库中设置要使用的模板。

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

但是,对于您来说最好的方法实际上取决于您加载用户首选项的方式以及UI的基本设计,MVVM vs MVC vs Custom Controls等。


0
你可以尝试类似于这样的代码:
<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>

代码后台:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接