我准备写一些桌面应用程序来嘲笑某些东西,我认为尝试一些ne技术是一个很好的机会。由于应用程序适用于Windows,我在某处看到了Visual Studio社区版,因此我决定尝试使用WPF。
所以这就是事情。基本视图应该看起来像一个简单的网格,其中每个矩形都是一个实际的TextBox。我可以点击并在每个文本中写下一些文字。
实现这个目标并不算太糟糕。起初我正在使用Grid和ColumnDefinitions以及RowDefinitions,这对硬编码很有用。之后,我尝试了一下使用ItemTemplate的ItemsControl,这就是它。
但现在有一个情节扭曲。我希望能够编辑每个TextBox。通过编辑,我的意思是将它分成几个较小的TextBoxes。因此,如果我将第二个分成2个,第三个分成3个,它应该是:
我不知道如何解决这个问题。由于它与其他的不一样,我认为我不能再将ItemsControl与模板一起使用(或者我可以吗?)。我对WPF很新,所以也许有一些我还没有见过的明显的东西。所以,如果那里有人非常了解WPF,并且可以指出我正确的方向,或者至少告诉我“你在做什么?WPF不适合那种应用程序,而是使用XXX”。
任何帮助/提示赞赏。
答案 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基础知识的一个很好的例子。
我为测试添加了一些边框,边距和背景颜色,这样你就可以看到哪个容器占用了什么空间。适合测试;可能在最终版本中删除或更改为透明。
<强>主窗口强>
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());
}
}
}