如何制作一个相似的物体网格?

时间:2016-03-08 00:55:06

标签: c# wpf wpf-controls

我准备写一些桌面应用程序来嘲笑某些东西,我认为尝试一些ne技术是一个很好的机会。由于应用程序适用于Windows,我在某处看到了Visual Studio社区版,因此我决定尝试使用WPF。

所以这就是事情。基本视图应该看起来像一个简单的网格,其中每个矩形都是一个实际的TextBox。我可以点击并在每个文本中写下一些文字。

Base grid

实现这个目标并不算太糟糕。起初我正在使用Grid和ColumnDefinitions以及RowDefinitions,这对硬编码很有用。之后,我尝试了一下使用ItemTemplate的ItemsControl,这就是它。



但现在有一个情节扭曲。我希望能够编辑每个TextBox。通过编辑,我的意思是将它分成几个较小的TextBoxes。因此,如果我将第二个分成2个,第三个分成3个,它应该是:

Edited grid

我不知道如何解决这个问题。由于它与其他的不一样,我认为我不能再将ItemsControl与模板一起使用(或者我可以吗?)。我对WPF很新,所以也许有一些我还没有见过的明显的东西。所以,如果那里有人非常了解WPF,并且可以指出我正确的方向,或者至少告诉我“你在做什么?WPF不适合那种应用程序,而是使用XXX”。


任何帮助/提示赞赏。

2 个答案:

答案 0 :(得分:1)

您可以使用ÌtemTemplateSelector根据变量分配不同的模板。

在您的代码中,我们有一个简单的Rows属性。这将用于显示网格中显示的行数。

MainWindow.cs

public partial class MainWindow : Window
{
    public int[] Rows{ get; set; }
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
        this.Rows= new int[] { 1, 2, 1, 3 };
    }
}

ItemTemplateSelector.cs根据DataTemplate选择正确的Rows

public class RowTemplateSelecter: DataTemplateSelector
{        
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        FrameworkElement element = container as FrameworkElement;
        int rows = 1;
        int.TryParse(item.ToString(), out rows);
        switch (rows)
        {
            case 1:
                return element.FindResource("OneRow") as DataTemplate;
            case 2:
                return element.FindResource("TwoRows") as DataTemplate;
            case 3:
                return element.FindResource("ThreeRows") as DataTemplate;
            default:
                return element.FindResource("OneRow") as DataTemplate;

        }          
    }
}

最后在MainWindow.xaml中添加我们的3个模板和ItemTemplateSelector

<Window.Resources>
    <DataTemplate x:Key="OneRow">
        <Grid Background="Red" Width="100" Height="100">

        </Grid>
    </DataTemplate>
    <DataTemplate x:Key="TwoRows" >
        <Grid Width="100" Height="100">
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Rectangle Fill="Blue"/>
            <Rectangle Fill="Green" Grid.Row="1"/>
        </Grid>
    </DataTemplate>
    <DataTemplate x:Key="ThreeRows">
        <Grid Width="100" Height="100">
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Rectangle Fill="Yellow"/>
            <Rectangle Fill="Orange" Grid.Row="1"/>
            <Rectangle Fill="Black" Grid.Row="2"/>
        </Grid>
    </DataTemplate>
    <local:RowTemplateSelecter x:Key="RowSelector"/>
</Window.Resources>
<Grid>
    <ItemsControl x:Name="rectangles"
                  ItemsSource="{Binding Rows}"
                  ItemTemplateSelector="{StaticResource RowSelector}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
</Grid>

希望有所帮助

答案 1 :(得分:1)

很好的问题,根据您的应用程序的功能,以及如何将每个控件的数据连接到您的应用程序/模型/其他任何内容,肯定有很多方法来布局控件。

此答案侧重于布局,同时占用所有可用空间并允许每个容器内的内容进行复制。内容流畅,直到窗口变得太小,太窄等等,这就是你需要决定你的应用程序允许用户做什么的地方。在此代码成为生产质量之前,还有很多工作要做,但是为了熟悉WPF平台,这是WPF基础知识的一个很好的例子。

我为测试添加了一些边框,边距和背景颜色,这样你就可以看到哪个容器占用了什么空间。适合测试;可能在最终版本中删除或更改为透明。

WPF Uniform Grid Sample by Kory Gill

<强>主窗口

XAML

<Grid x:Name="LayoutRoot">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <StackPanel>
        <TextBlock Text="WPF" FontSize="36" Margin="20" Foreground="Orange" HorizontalAlignment="Center"/>
    </StackPanel>
    <Grid Grid.Row="1" Margin="5">
        <Border Background="LightGray" BorderBrush="Red" BorderThickness="1">
            <UniformGrid Columns="4" Name="MainPanel"/>
        </Border>
    </Grid>
</Grid>

代码

public partial class MainWindow : Window
{
    private static int _nextId = 0;
    public static int NextId
    {
        get { return _nextId++; }
    }

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
        Loaded += MainWindow_Loaded;
    }

    private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        // add non-multiple of 8 to see how layout works
        for (var i=0; i<7; i++)
        {
            MainPanel.Children.Add(new EditPanelControl());
        }
    }
}

EditPanelControl(用户控件)

XAML

<Grid Margin="5">
    <Border Background="LightYellow" BorderBrush="Green" BorderThickness="1">
        <!-- Make this a viewbox if you want to show all items but have them shrink -->
        <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
            <StackPanel Name="MainPanel" VerticalAlignment="Center"/>
        </ScrollViewer>
    </Border>
</Grid>

代码

public partial class EditPanelControl : UserControl
{
    public EditPanelControl()
    {
        InitializeComponent();
        DataContext = this;
        Loaded += EditPanelControl_Loaded;
    }

    private void EditPanelControl_Loaded(object sender, RoutedEventArgs e)
    {
        AddSuperTextControl();
    }

    private void AddSuperTextControl()
    {
        var stc = new SuperTextControl();
        stc.SplitEvent += Stc_SplitEvent;
        stc.DeleteEvent += Stc_DeleteEvent;
        stc.SuperTextBox.Text = MainWindow.NextId.ToString();
        MainPanel.Children.Add(stc);
    }

    private void Stc_DeleteEvent(object sender, EventArgs e)
    {
        // todo: don't allow delete if only 1 child
        var stc = (SuperTextControl)sender;
        MainPanel.Children.Remove(stc);
    }

    private void Stc_SplitEvent(object sender, EventArgs e)
    {
        var stc = (SuperTextControl)sender; // fyi
        AddSuperTextControl();
    }
}

SuperTextControl(用户控件)

XAML

<Grid Margin="5">
    <Border Background="Wheat" BorderBrush="Blue" BorderThickness="1">
        <StackPanel VerticalAlignment="Center" HorizontalAlignment="Stretch">
            <TextBox Name="SuperTextBox" Margin="5"/>
            <DockPanel LastChildFill="False" Margin="0,0,0,5">
                <Button Content="Split" Click="SplitHandler" Margin="5,0" DockPanel.Dock="Left"/>
                <Button Content="Delete" Click="DeleteHandler" Margin="5,0" DockPanel.Dock="Right"/>
            </DockPanel>
        </StackPanel>
    </Border>
</Grid>

代码

public partial class SuperTextControl : UserControl
{
    public event EventHandler SplitEvent;
    public event EventHandler DeleteEvent;

    public SuperTextControl()
    {
        InitializeComponent();
    }

    private void SplitHandler(object sender, RoutedEventArgs e)
    {
        var button = (Button)sender; // fyi

        if (SplitEvent != null)
        {
            SplitEvent(this, new EventArgs());
        }
    }

    private void DeleteHandler(object sender, RoutedEventArgs e)
    {
        var button = (Button)sender; // fyi

        if (DeleteEvent != null)
        {
            DeleteEvent(this, new EventArgs());
        }
    }
}