WPF 优化 XAML 代码

Posted

技术标签:

【中文标题】WPF 优化 XAML 代码【英文标题】:WPF Optimize XAML code 【发布时间】:2014-04-02 19:35:43 【问题描述】:

有没有更有效的方式来编写以下 XAML 代码? (当我说更高效时,我的意思是更少重复)。尤其是超链接和扩展器。谢谢!

<Window x:Class="InterfazOhmio.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Background>
        <ImageBrush ImageSource="Imagenes/background.jpg"></ImageBrush>
    </Window.Background>
    <Grid>       
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <ListBox ScrollViewer.VerticalScrollBarVisibility="Auto">
            <ListBox.Resources>
                <Style TargetType="x:Type Expander">
                    <Setter Property="IsExpanded"
           Value="Binding Path=IsSelected, RelativeSource=RelativeSource AncestorType=x:Type ListBoxItem"/>
                </Style>
            </ListBox.Resources>
            <ListBox.Template>
                <ControlTemplate TargetType="x:Type ListBox">
                    <ItemsPresenter/>
                </ControlTemplate>
            </ListBox.Template>
            <ListBox.ItemContainerStyle>
                <Style TargetType="x:Type ListBoxItem">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="x:Type ListBoxItem">
                                <ContentPresenter Content="TemplateBinding Content"/>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </ListBox.ItemContainerStyle>            

            <Expander Margin="2" Background="OliveDrab">                
                <Expander.Header>
                    <BulletDecorator>
                        <BulletDecorator.Bullet>
                            <Image Source="Iconos/Pedidos.png" Width="64" Height="64" HorizontalAlignment="Left" VerticalAlignment="Top" />                            
                        </BulletDecorator.Bullet>                        
                        <TextBlock Margin="10,0,0,0" Text="Pedidos" VerticalAlignment="Center" HorizontalAlignment="Stretch" Foreground="White" />
                    </BulletDecorator>
                </Expander.Header>
                <WrapPanel>
                    <Label Margin="20,5,5,5" HorizontalAlignment="Stretch">
                        <Hyperlink TextDecorations="None">
                            <TextBlock Foreground="White" Text="Nuevo Pedido"/>
                        </Hyperlink>
                    </Label>
                    <Label Margin="20,5,5,5" HorizontalAlignment="Stretch">
                        <Hyperlink TextDecorations="None">
                            <TextBlock Foreground="White" Text="Consultar Pedidos" />
                        </Hyperlink>
                    </Label>
                    <Label Margin="20,5,5,5" HorizontalAlignment="Stretch">
                        <Hyperlink TextDecorations="None">
                            <TextBlock Foreground="White" Text="Pedidos Pendientes" />
                        </Hyperlink>
                    </Label>                                 
                </WrapPanel>
            </Expander>

            <Expander Margin="2" Background="OrangeRed">
                <Expander.Header>
                    <BulletDecorator>
                        <BulletDecorator.Bullet>
                            <Image Source="Iconos/Remitos.png" Width="64" Height="64" HorizontalAlignment="Left" VerticalAlignment="Top" />
                        </BulletDecorator.Bullet>
                        <TextBlock Margin="10,0,0,0" Text="Remitos" VerticalAlignment="Center" HorizontalAlignment="Stretch" Foreground="White" />
                    </BulletDecorator>
                </Expander.Header>
                <WrapPanel>                    
                    <Label Margin="20,5,5,5" HorizontalAlignment="Stretch">
                        <Hyperlink TextDecorations="None">
                            <TextBlock Foreground="White" Text="Nuevo Remito"/>
                        </Hyperlink>
                    </Label>
                    <Label Margin="20,5,5,5" HorizontalAlignment="Stretch">
                        <Hyperlink TextDecorations="None">
                            <TextBlock Foreground="White" Text="Consultar Remitos" />
                        </Hyperlink>
                    </Label>
                    <Label Margin="20,5,5,5" HorizontalAlignment="Stretch">
                        <Hyperlink TextDecorations="None">
                            <TextBlock Foreground="White" Text="Remitos Pendientes" />
                        </Hyperlink>
                    </Label>
                </WrapPanel>
            </Expander>

            <Expander Margin="2" Background="Teal">
                <Expander.Header>
                    <BulletDecorator>                        
                        <BulletDecorator.Bullet>
                            <Image Source="Iconos/Facturas.png" Width="64" Height="64" HorizontalAlignment="Left" VerticalAlignment="Top" />
                        </BulletDecorator.Bullet>
                        <TextBlock Margin="10,0,0,0" Text="Facturas" VerticalAlignment="Center" HorizontalAlignment="Stretch" Foreground="White" />
                    </BulletDecorator>
                </Expander.Header>
                <StackPanel>
                    <Label Margin="20,5,5,5" HorizontalAlignment="Stretch">
                        <Hyperlink TextDecorations="None">
                            <TextBlock Foreground="White" Text="Nueva Factura"/>
                        </Hyperlink>
                    </Label>
                    <Label Margin="20,5,5,5" HorizontalAlignment="Stretch">
                        <Hyperlink TextDecorations="None">
                            <TextBlock Foreground="White" Text="Consultar Facturas" />
                        </Hyperlink>
                    </Label>                    
                </StackPanel>
            </Expander>          

        </ListBox>        
    </Grid>    
</Window>

更新

好的,我尝试了建议的解决方案,它可以工作,但结果中存在一些小的视觉差异,如当时的图片所示:

左侧是原始菜单。右侧是带有 viewModel 的新视图:

选择项被标记,而不是在原始菜单中。 扩展器的宽度太短

这是 XAML 的结果:

<Window x:Class="InterfazOhmio.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:InterfazOhmio"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <Window.Background>
        <ImageBrush ImageSource="Imagenes/background.jpg"></ImageBrush>
    </Window.Background>
    <Grid>       
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200"></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <ListBox ItemsSource="Binding myMenu">
            <ListBox.Resources>
                <Style TargetType="x:Type Expander">
                    <Setter Property="IsExpanded"
           Value="Binding Path=IsSelected, RelativeSource=RelativeSource AncestorType=x:Type ListBoxItem"/>
                </Style>
            </ListBox.Resources>
            <ListBox.Template>
                <ControlTemplate TargetType="x:Type ListBox">
                    <ItemsPresenter/>
                </ControlTemplate>
            </ListBox.Template>

            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Expander Margin="2" Background="Binding Color">
                        <Expander.Header>
                            <BulletDecorator>
                                <BulletDecorator.Bullet>
                                    <Image Source="Binding ImageSource" Width="64" Height="64" HorizontalAlignment="Left" VerticalAlignment="Top" />
                                </BulletDecorator.Bullet>
                                <TextBlock Margin="10,0,0,0" Text="Binding Title" VerticalAlignment="Center" HorizontalAlignment="Stretch" Foreground="White" />
                            </BulletDecorator>
                        </Expander.Header>
                        <ListBox ItemsSource="Binding Options" Background="Transparent">
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <Label Margin="20,5,5,5" HorizontalAlignment="Stretch">
                                        <Hyperlink TextDecorations="None">
                                            <TextBlock Foreground="White" Text="Binding"/>
                                        </Hyperlink>
                                    </Label>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>
                    </Expander>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>    
</Window>

有人可以帮我吗?谢谢! 更新二

差不多了!!!

XAML:

<Window x:Class="InterfazOhmio.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:InterfazOhmio"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <Window.Background>
        <ImageBrush ImageSource="Imagenes/background.jpg"></ImageBrush>
    </Window.Background>
    <Grid>       
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200"></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <ItemsControl ItemsSource="Binding myMenu">
            <ItemsControl.Resources>
                <Style TargetType="x:Type Expander">
                    <Setter Property="IsExpanded"
           Value="Binding Path=IsSelected, RelativeSource=RelativeSource AncestorType=x:Type ListBoxItem"/>
                </Style>
            </ItemsControl.Resources>
            <ItemsControl.Template>
                <ControlTemplate TargetType="x:Type ItemsControl">
                    <ItemsPresenter/>
                </ControlTemplate>
            </ItemsControl.Template>

            <ItemsControl.ItemTemplate>
                <DataTemplate>                    
                    <Expander Margin="2" Width="196" Background="Binding Color">                        
                        <Expander.Header>
                            <BulletDecorator>
                                <BulletDecorator.Bullet>
                                    <Image Source="Binding ImageSource" Width="64" Height="64" HorizontalAlignment="Left" VerticalAlignment="Top" />
                                </BulletDecorator.Bullet>
                                <TextBlock Margin="10,0,0,0" Text="Binding Title" VerticalAlignment="Center" HorizontalAlignment="Stretch" Foreground="White" />
                            </BulletDecorator>
                        </Expander.Header>
                        <ItemsControl ItemsSource="Binding Options" Background="Transparent" BorderThickness="0">
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <Label Margin="20,5,5,5" HorizontalAlignment="Stretch">
                                        <Hyperlink TextDecorations="None">
                                            <TextBlock Foreground="White" Text="Binding"/>
                                        </Hyperlink>
                                    </Label>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                    </Expander>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>    
</Window>

我将列表框替换为 ItemsControl。现在唯一不起作用的是一次只能扩展一个扩展器。我想问题是这段代码:

         <ItemsControl.Resources>
                <Style TargetType="x:Type Expander">
                    <Setter Property="IsExpanded"
           Value="Binding Path=IsSelected, RelativeSource=RelativeSource AncestorType=x:Type ListBoxItem"/>
                </Style>
            </ItemsControl.Resources>
            <ItemsControl.Template>
                <ControlTemplate TargetType="x:Type ItemsControl">
                    <ItemsPresenter/>
                </ControlTemplate>
            </ItemsControl.Template>

因为它指向 ListBoxItem 类。问题是 ItemsControlItem 类不存在。是现在唯一的问题!!!

【问题讨论】:

这可能更适合CodeReview 或Programmers 但无论如何都会看看,因为这种事情很有趣。 为了隐藏选择,我发现了这个(参见关于设置 ListBoxItem 样式资源的答案的更新部分):***.com/questions/3351904/… 为宽度,在列表框上设置 Horizo​​ntalContentAlignment="Center" ---您可能还想在最里面的列表框(子项)上设置 BorderThickness="0" 随时将您的更新移至我的答案中,以使其成为更明确的问答 根据我的发现,ItemsControl 不会跟踪 SelectedItem,而这正是您用作要展开的触发器的内容。 【参考方案1】:

可以使用 ViewModel 来完成,然后将 xaml 归结为单个项目作为模板:

为虚拟机设置上下文

<Window.DataContext>
    <local:ViewModel />
</Window.DataContext>

快速而肮脏的虚拟机和模型

public class ViewModel

    public ObservableCollection<Item> Items  get; set; 

    public ViewModel()
    
        Items = new ObservableCollection<Item>()  new Item()  Title="Pedidos", ImageSource="Iconos/Pedidos.png", Color=new SolidColorBrush(Colors.OliveDrab), Options = new List<string>()"Nuevo Pedido","Consultar Pedidos","Pedidos Pendientes" ,
                                                   new Item()  Title="Remitos", ImageSource="Iconos/Remitos.png", Color=new SolidColorBrush(Colors.OrangeRed), Options = new List<string>()"Nuevo Remito","Consultar Remitos","Remitos Pendientes" ,
                                                   new Item()  Title="Facturas", ImageSource="Iconos/Facturas.png", Color=new SolidColorBrush(Colors.Teal), Options = new List<string>()"Nuevo Factura","Consultar Facturas"  ;
    

public class Item

    public string Title  get; set; 
    public List<string> Options  get; set; 
    public SolidColorBrush Color  get; set; 
    public string ImageSource  get; set; 


然后是 XAML...

物品来源

<ListBox ItemsSource="Binding Items">

项目模板

       <ItemsControl.ItemTemplate>
            <DataTemplate>                    
                <Expander Margin="2" Width="196" Background="Binding Color">                        
                    <Expander.Header>
                        <BulletDecorator>
                            <BulletDecorator.Bullet>
                                <Image Source="Binding ImageSource" Width="64" Height="64" HorizontalAlignment="Left" VerticalAlignment="Top" />
                            </BulletDecorator.Bullet>
                            <TextBlock Margin="10,0,0,0" Text="Binding Title" VerticalAlignment="Center" HorizontalAlignment="Stretch" Foreground="White" />
                        </BulletDecorator>
                    </Expander.Header>
                    <ItemsControl ItemsSource="Binding Options" Background="Transparent" BorderThickness="0">
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <Label Margin="20,5,5,5" HorizontalAlignment="Stretch">
                                    <Hyperlink TextDecorations="None">
                                        <TextBlock Foreground="White" Text="Binding"/>
                                    </Hyperlink>
                                </Label>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                </Expander>
            </DataTemplate>
        </ItemsControl.ItemTemplate>

【讨论】:

这太棒了!特别是因为在我的应用程序中,我正在尝试遵循 MVVM 模式,所以已经有一个 ViewModel!我会试试的,但它看起来很棒!谢谢!!! 我更新您的答案并发布最后一次更新。差不多了!

以上是关于WPF 优化 XAML 代码的主要内容,如果未能解决你的问题,请参考以下文章

将 WPF XAML 代码移植到 Silverlight XAML 代码

在WPF中,如何得到任何Object对象的XAML代码?

(WPF)XAML 过程式代码

WPF 修改(优化)Menu菜单的样式

WPF 获取xaml

WPF如何更改xaml代码里ListBox的数据绑定