wpf - 如何重新设计控件的样式以在 WPF 中具有特定的 UI

标签 wpf wpf-controls

这里我给出了一个控件的图像,它将显示许多图像的缩略图,并且用户可以在图像之间滚动。用户可以设置每行显示多少图像。用户可以设置显示多少行并可以进行数据绑定(bind)等。

enter image description here

我是 WPF 新手。所以请指导我如何绘制上面那样的输出。谢谢

更新

enter image description here

enter image description here

最佳答案

据我了解,您需要添加向上、向下,这将滚动 ListBox 与图像。 ListBox 已经包含一个带有标准滚动条的 ScrollViewer。我建议我们应该隐藏标准滚动条,并为自己设置导航按钮。

这些按钮的功能将引用标准的ScrollViewer。为了访问 ListBox 中的 ScrollViewer,您必须使用以下函数:

public static DependencyObject GetScrollViewer(DependencyObject Object)
{
    if (Object is ScrollViewer)
    {
        return Object;
    }

    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(Object); i++)
    {
        var child = VisualTreeHelper.GetChild(Object, i);
        var result = GetScrollViewer(child);

        if (result == null)
        {
            continue;
        }
        else
        {
            return result;
        }
    }

    return null;
}

VisualTreeHelper的帮助下,该函数返回一个ScrollViewer类型的对象。

垂直向上导航如下:

scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - 30);

我们为按钮定义一种样式,其中将包含箭头形式的Path。下面是带有注释的完整示例。

XAML

<Window x:Class="CustomListboxNavHelp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:CustomListboxNavHelp"
    Title="MainWindow" Height="450" Width="525"
    WindowStartupLocation="CenterScreen"
    ContentRendered="Window_ContentRendered">

<Window.Resources>      
    <!-- Style for ListBox -->
    <Style x:Key="MyListBoxStyle" TargetType="{x:Type ListBox}">
        <Setter Property="BorderThickness" Value="1" />
        <Setter Property="BorderBrush" Value="Transparent" />
        <Setter Property="ScrollViewer.CanContentScroll" Value="False" />
        <Setter Property="HorizontalAlignment" Value="Center" />

        <!-- Hidden Scrollbar`s -->
        <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden" />
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" />

        <!-- DataTemplate for ListBoxItem -->
        <Setter Property="ItemTemplate">
            <Setter.Value>
                <DataTemplate>
                    <Border BorderBrush="Transparent" BorderThickness="1">
                        <Image Source="{Binding Path=MyImagePath}" Stretch="Fill" Width="100" Height="140" />
                    </Border>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!-- Style for UpButton -->
    <Style x:Key="UpButtonStyle" TargetType="{x:Type Button}">
        <Setter Property="Background" Value="Transparent" />
        <Setter Property="FocusVisualStyle" Value="{x:Null}" />
        <Setter Property="SnapsToDevicePixels" Value="True" />
        <Setter Property="ToolTip" Value="Up" />

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Border CornerRadius="0" Background="{TemplateBinding Background}">
                        <Grid>
                            <ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" />
                            <Path x:Name="UpButton" SnapsToDevicePixels="True" Width="20" Height="18" Stretch="Fill" Fill="Gray" Data="F1 M 37.8516,35.625L 34.6849,38.7917L 23.6016,50.2708L 23.6016,39.9792L 37.8516,24.9375L 52.1016,39.9792L 52.1016,50.2708L 41.0182,38.7917L 37.8516,35.625 Z "/>
                        </Grid>
                    </Border>

                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="UpButton" Property="Fill" Value="Black" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!-- Style for DownButton -->
    <Style x:Key="DownButtonStyle" TargetType="{x:Type Button}">
        <Setter Property="Background" Value="Transparent" />
        <Setter Property="FocusVisualStyle" Value="{x:Null}" />
        <Setter Property="SnapsToDevicePixels" Value="True" />
        <Setter Property="ToolTip" Value="Down" />

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Border CornerRadius="0" Background="{TemplateBinding Background}">
                        <Grid>
                            <ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" />
                            <Path x:Name="DownButton" SnapsToDevicePixels="True" Width="20" Height="18" Stretch="Fill" Fill="Gray" Data="F1 M 37.8516,39.5833L 52.1016,24.9375L 52.1016,35.2292L 37.8516,50.2708L 23.6016,35.2292L 23.6016,24.9375L 37.8516,39.5833 Z "/>
                        </Grid>
                    </Border>

                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="DownButton" Property="Fill" Value="Black" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

<Grid>
    <StackPanel>
        <Button Name="UpDirection" Style="{StaticResource UpButtonStyle}" Width="40" Height="30" Click="UpDirection_Click" />

        <ListBox Name="MyListBox" Style="{StaticResource MyListBoxStyle}" Width="110" Height="300" />

        <Button Name="DownDirection" Style="{StaticResource DownButtonStyle}" Width="40" Height="30" Click="DownDirection_Click" />
    </StackPanel>
</Grid>
</Window>

隐藏代码

public partial class MainWindow : Window
{
    private ObservableCollection<ImagesClass> ImagesCollection = new ObservableCollection<ImagesClass>();

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Window_ContentRendered(object sender, EventArgs e)
    {
        ImagesCollection.Add(new ImagesClass()
        {
            MyImagePath = "Cover1.png"     // Images must be in resource
        });

        ImagesCollection.Add(new ImagesClass()
        {
            MyImagePath = "Cover2.png"
        });

        ImagesCollection.Add(new ImagesClass()
        {
            MyImagePath = "Cover3.png"
        });

        ImagesCollection.Add(new ImagesClass()
        {
            MyImagePath = "Cover4.png"
        });

        ImagesCollection.Add(new ImagesClass()
        {
            MyImagePath = "Cover5.png"
        });

        ImagesCollection.Add(new ImagesClass()
        {
            MyImagePath = "Cover6.png"
        });

        MyListBox.ItemsSource = ImagesCollection;
    }

    private void UpDirection_Click(object sender, RoutedEventArgs e)
    {
        NavigationInScrollViewer(MyListBox, "Up", 40);
    }

    private void DownDirection_Click(object sender, RoutedEventArgs e)
    {
        NavigationInScrollViewer(MyListBox, "Down", 40);
    }

    /// <summary>
    /// Vertical navigation for ListBox
    /// </summary>
    /// <param name="myListbox">ListBox</param>
    /// <param name="direction">Direction for scrolling</param>
    /// <param name="offset">Offset</param>
    private void NavigationInScrollViewer(ListBox myListbox, string direction, int offset) 
    {
        ScrollViewer scrollViewer = GetScrollViewer(MyListBox) as ScrollViewer;

        if (direction == "Up") 
        {
            if (scrollViewer != null)
            {
                scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - offset);
            }
        }

        if (direction == "Down") 
        {                
            if (scrollViewer != null)
            {
                scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + offset);
            }
        }
    }

    /// <summary>
    /// Get ScrollViewer from Control
    /// </summary>
    /// <param name="Object">Dependency object</param>
    /// <returns>ScrollViewer control</returns>
    public static DependencyObject GetScrollViewer(DependencyObject Object)
    {
        if (Object is ScrollViewer)
        {
            return Object;
        }

        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(Object); i++)
        {
            var child = VisualTreeHelper.GetChild(Object, i);
            var result = GetScrollViewer(child);

            if (result == null)
            {
                continue;
            }
            else
            {
                return result;
            }
        }

        return null;
    }
}

/// <summary>
/// Class contain paths to images
/// </summary>
public class ImagesClass
{
    private string myImagePath = null;

    public string MyImagePath
    {
        get
        {
            return myImagePath;
        }

        set
        {
            myImagePath = value;
        }
    }
}

输出

enter image description here

编辑:

要在单个 ListBoxItem 中显示多个图像,您需要更正 ItemTemplate。我建议使用 Grid,因为它是 ColumnDefenition 的一个属性,用于定义项目的列号。

另一件事是你知道这是可取的:

  • 一个 ListBoxItem 中显示的最终图像数量。

  • 对于大量图片需要改进方法,因为它更适合静态显示。

正确的ItemTenplate,如下所示:

<Setter Property="ItemTemplate">
    <Setter.Value>
        <DataTemplate>
            <Border BorderBrush="Transparent" BorderThickness="1">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>

                    <Image Source="{Binding Path=MyImagePathOne}" Grid.Column="0" Stretch="Fill" Width="100" Height="140" />
                    <Image Source="{Binding Path=MyImagePathTwo}" Grid.Column="1" Stretch="Fill" Width="100" Height="140" />
                </Grid>
            </Border>
       </DataTemplate>
   </Setter.Value>
</Setter>

图像类

public class ImagesClass
{
    private string myImagePathOne = null;

    public string MyImagePathOne
    {
        get
        {
            return myImagePathOne;
        }

        set
        {
            myImagePathOne = value;
        }
    }

    private string myImagePathTwo = null;

    public string MyImagePathTwo
    {
        get
        {
            return myImagePathTwo;
        }

        set
        {
            myImagePathTwo = value;
        }
    }
}

将图像添加到集合中:

ImagesCollection.Add(new ImagesClass()
{
    MyImagePathOne = "Cover1.png",
    MyImagePathTwo = "Cover2.png"
});

ImagesCollection.Add(new ImagesClass()
{
    MyImagePathOne = "Cover3.png",
    MyImagePathTwo = "Cover4.png"
});

ImagesCollection.Add(new ImagesClass()
{
    MyImagePathOne = "Cover5.png",
    MyImagePathTwo = "Cover6.png"
});

输出

enter image description here

如果你确实需要动态改变图像的数量,从这种情况来看,你可以这样做——设置属性所在的集合,例如仅单个图像。然后,将其清理并以任意数量的图像将其放置在设定值上。

我认为这个方法并不是百分百适合这个方法。如果速度很重要,或者图像数量很大,就需要优化方法,或者想出另一种方法。

编辑2

向上和向下按钮:

<Button Name="Up" Width="150" Height="15" Background="#CDE2FF">
    <Button.Content>
        <Polygon Points="3.33,0 6.66,6.66, 0,6.66" Fill="#466690" />
    </Button.Content>
</Button>

<Button Name="Down" Width="150" Height="15" Background="#CDE2FF" Margin="0,10,0,0">
    <Button.Content>
        <Polygon Points="0,0 3.33,6.66, 6.66,0" Fill="#466690" />
    </Button.Content>
</Button>

输出

enter image description here

关于wpf - 如何重新设计控件的样式以在 WPF 中具有特定的 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18207412/

相关文章:

c# - WPF 用户控件最大化时全屏?

c# - 如何缩小文本 block 中的字体大小以适应内容的宽度并保持字体纵横比

wpf - 向 WPF 控件工具提示添加条件可见性

c# - WPF DataGrid 行颜色基于变量变化

c# - PresentationFramework 中的 NullReference 异常

c# - WPF 组合框 - 按标签选择项目

c# - 让用户选择要在 WPF DataGrid 上显示的列

wpf - 带有包含按钮的 ItemTemplate 的 ComboBox

wpf - 按键事件 : how to capture down and up key rows?

c# - WPF DependencyProperty 抛出 InvalidOperationException