Fluid layout wrap panel / VariableSizedWrapGrid in

2019-02-03 15:16发布

问题:

Is it possible to use the VariableSizedWrapGrid control in desktop apps (i.e. Windows 7 WPF applications)? Presently this control only seems available in WinRT, Windows 8, Windows Phone, etc. If it's possible, how? Otherwise, what option would I have to get the same sort of functionality?

For those who aren't familiar with the concept, it would be similar to a WrapPanel, however elements would fill open spaces in the panel rather than spill over onto the next row, like so (see also Masonry for jQuery):

回答1:

I ended up utilizing Lizzaran's WPF-Masonry library, which is pretty nice. It didn't come with any dependency properties for proper binding, but it wouldn't be difficult to add them. I'm also using MahApps' latest Metro library (different than the one that's available through nuget) for their tile control, but that's not necessary.

Here's what it ended up looking like:

Here is the brunt of the code:

MainWindow.xaml:

<Window x:Class="TileExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Masonry="clr-namespace:MasonryLibrary;assembly=MasonryLibrary"
        Title="Tiles"
        Loaded="Window_Loaded"
        Height="400"
        Width="600">
  <Grid>
    <Masonry:Masonry x:Name="ui_masonry"
                     VerticalAlignment="Top"
                     Animation="False">
    </Masonry:Masonry>
  </Grid>
</Window>

MainWindow.xaml.cs:

private void Window_Loaded(object sender, RoutedEventArgs e) {
  for (int i = 0; i < 15; i++) {
    var tile = new Tile();
    tile.Header = i.ToString();
    ui_masonry.Add(tile);
  }
}

Tile.xaml:

<UserControl x:Class="TileExample.Tile"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
             mc:Ignorable="d"
             Width="140"
             Height="140"
             Name="ui_ctrl"
             d:DesignHeight="300"
             d:DesignWidth="300">
  <UserControl.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colours.xaml" />
        <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
        <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
        <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.AnimatedSingleRowTabControl.xaml" />
        <ResourceDictionary Source="pack://application:,,,/MahApps.Metro.Resources;component/Icons.xaml" />
        <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
        <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
        <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/FlatSlider.xaml" />
        <ResourceDictionary Source="/Resources/Effects/Animations.xaml" />
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </UserControl.Resources>
  <Controls:Tile Title="Not Used"
                 x:Name="ui_tile"
                 Click="Tile_Click">
    <ItemsControl x:Name="ui_tile_content">
    </ItemsControl>
  </Controls:Tile>
</UserControl>

Tile.xaml.cs:

  public partial class Tile : UserControl {

    public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header",
                                                                                       typeof(string),
                                                                                       typeof(Tile));
    public Tile() {
      InitializeComponent();
    }

    private void Tile_Click(object sender, RoutedEventArgs e) {
      //Your animation code here...
      //I utilized some animations from my own library for this that simply
      //expands the tile to twice its width and height
    }

    public string Header {
      get { return (string)GetValue(HeaderProperty); }
      set {
        SetValue(HeaderProperty, value);
        ui_tile.Title = value;
      }
    }
  }

I added some animations to my tiles so that they expand when a user clicks on them. The Masonry library performs pretty well with an occasional glitch, but I'm pretty happy with how it turned out. I eventually added some UI logic to only allow for one tile to be expanded at time.