【论论】WPF中用什么控件承载应用程序的“设置(选项)”窗体中右侧的设置区域内容 本帖最后由 aresskyaressky 于 2014-08-13 11:50:12 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 这是一种典型的切换情况。1:WPF虽然提供了Canvas,但是它用于UIElement元素定位,并不是你再使用一个ScrollViewer,就能达到理想的效果,因为还要计算垂直的Offset。2: 形成平面效果,那就要修改模板,而且效果并不会太好。3:你自己都觉得麻烦。4:既然要进行保存操作,那么对保存的数据的储存就要相当的清晰。不要说什么 统一保存。把数据存放到ObservableCollection中,直至所有操作完成,就行统一的保存。个人感觉, 知道ContentControl控件的使用,会让你觉得如此简单。 把每个左侧显示的布局结构 做成用户控件,通过点击 左侧的TreeViewItem 对ContentControl 的Content属性进行设置,就可以实现切换。每一个UserControl 对应一个集合,最终保存再操作集合,更新到数据库或者其它文件。PS:个人断点,不喜勿喷。 比较方便的做法是采用数据绑定,并配合数据模版(DataTemplate)。好处一,是可以根据不同的数据,自动适用配合的模版。好处二,是容易进一步改为MVVM模式。比如下面的例子,有两个类,GeneralSettings和EditorSettings,它们都继承于SettingBase。一个ListView绑定到一个SettingBase的集合上。要添加新的Setting,可以简单地继承于SettingBase,并放到集合内。编辑由一个ContentControl来完成,它的内容绑定到ListView的当前选择项,根据当前选择项的数据类型,使用相应的模版来提供具体的编辑界面。<Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <ResourceDictionary> <!-- 用于展现常规设置的数据模版 --> <DataTemplate DataType="{x:Type local:GeneralSettings}"> <StackPanel> <TextBlock Height="40" Background="PeachPuff" TextAlignment="Center" FontSize="16" Text="{Binding Name}" /> <StackPanel Orientation="Horizontal"> <CheckBox IsChecked="{Binding CanUpload}" Content="允许上传数据" /> </StackPanel> </StackPanel> </DataTemplate> <!-- 用于展现编辑设置的数据模版 --> <DataTemplate DataType="{x:Type local:EditorSettings}"> <StackPanel> <TextBlock Height="40" Background="Wheat" TextAlignment="Center" FontSize="16" Text="{Binding Name}" /> <StackPanel Orientation="Horizontal"> <TextBlock Text="颜色" Height="30"/> <TextBox Text="{Binding Color}" Width="100" Height="30" Margin="12,0,0,0"/> <Grid Background="{Binding Color}" Width="100" Height="30" /> </StackPanel> <CheckBox IsChecked="{Binding AutoWrap}" Content="自动换行" /> </StackPanel> </DataTemplate> </ResourceDictionary> </Window.Resources> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*" /> <ColumnDefinition Width="4*" /> </Grid.ColumnDefinitions> <ListView Name="settingList" ItemsSource="{Binding}"> <ListView.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Name}" /> </DataTemplate> </ListView.ItemTemplate> </ListView> <!-- ContentControl的内容绑定到ListView的SelectedItem,具体的UI由DataTemplate提供--> <ContentControl Grid.Column="1" Content="{Binding SelectedItem, ElementName=settingList}"></ContentControl> </Grid></Window>using System.Collections.ObjectModel;using System.ComponentModel;using System.Windows;namespace WpfApplication1{ public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); settings.Add(new GeneralSettings()); settings.Add(new EditorSettings()); // 这里可以添加新的设置 // settings.Add(...); this.DataContext = settings; } ObservableCollection<SettingBase> settings = new ObservableCollection<SettingBase>(); } public class SettingBase : INotifyPropertyChanged { public virtual string Name { get; set; } public event PropertyChangedEventHandler PropertyChanged = delegate { }; protected void FirePropertyChanged(string propertyName) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public class GeneralSettings : SettingBase { public GeneralSettings() { this.Name = "常规设置"; } private bool canUpload; public bool CanUpload { get { return canUpload; } set { if (canUpload != value) { canUpload = value; FirePropertyChanged("CanUpload"); } } } } public class EditorSettings : SettingBase { public EditorSettings() { this.Name = "编辑设置"; this.Color = "#AA8844"; } private string color; public string Color { get { return color; } set { if (color != value) { color = value; FirePropertyChanged("Color"); } } } public bool AutoWrap { get; set; } }} 根据你的源码,我已经实现了从左边点击ListBox的项目,右侧ContentControl加载相应的DataTemplate,因为DataTemplate的内容不能在VS或Blend中直接编辑,我就把他做成了控件引用到了DataTemplate中,现在还有一个问题。我左侧的菜单不是采用TreeView或ListView,而是多个Expander+ListBox的形式。而ContentControl只能绑定到其中的一个ListBox上,试了好多方法都无法实现将当前展开的Expander中的ListBox实时绑定到ContentControl中。 把你的方法和3楼的结合了一下,现在还有一个问题。我左侧的菜单不是采用TreeView或ListView,而是多个Expander+ListBox的形式。而ContentControl只能绑定到其中的一个ListBox上,试了好多方法都无法实现将当前展开的Expander中的ListBox实时绑定到ContentControl中。需要再开个贴来问吗? 前台Binding实在是搞不出来,只能后台用C#实现了 private void Expaner2_Expanded_1(object sender, RoutedEventArgs e) { //将ContentControl的content绑定到SettingList2这个ListBox中 Binding binding = new Binding {ElementName = "SettingList2", Path = new PropertyPath("SelectedItem")}; CcSettings.SetBinding(ContentControl.ContentProperty, binding); } private void Expander1_Expanded_1(object sender, RoutedEventArgs e) { //将ContentControl的content绑定到SettingList2这个ListBox中 Binding binding = new Binding { ElementName = "SettingList1", Path = new PropertyPath("SelectedItem") }; CcSettings.SetBinding(ContentControl.ContentProperty, binding); } 倒是不用改变Binding。用代码可以直接设置Content。CcSettings.Content = SettlingList2.SelectedItem; 求高手帮忙解析XML [新手求助]定义枚举出错,为什么? 求C# Xml方面的好书推荐 为什么我的C#连接时候要指明服务器名呢?不能用一个点来连接本地的SQL2005? 如何操作DataTable? 关于hashtable的小问题 求救~!关于分页的CurrentPageIndex的变更 DateTimePicker 颜色相关的问题.看者有分 ********新手提个小问题********* C# TreeView去除点击背景色问题 C# 多个oracle 数据库事务怎么处理??? 求winform文本编辑器
1:WPF虽然提供了Canvas,但是它用于UIElement元素定位,并不是你再使用一个ScrollViewer,就能达到理想的效果,因为还要计算垂直的Offset。
2: 形成平面效果,那就要修改模板,而且效果并不会太好。
3:你自己都觉得麻烦。
4:既然要进行保存操作,那么对保存的数据的储存就要相当的清晰。不要说什么 统一保存。把数据存放到ObservableCollection中,直至所有操作完成,就行统一的保存。个人感觉, 知道ContentControl控件的使用,会让你觉得如此简单。 把每个左侧显示的布局结构 做成用户控件,通过点击 左侧的TreeViewItem 对ContentControl 的Content属性进行设置,就可以实现切换。
每一个UserControl 对应一个集合,最终保存再操作集合,更新到数据库或者其它文件。
PS:个人断点,不喜勿喷。
好处一,是可以根据不同的数据,自动适用配合的模版。
好处二,是容易进一步改为MVVM模式。比如下面的例子,有两个类,GeneralSettings和EditorSettings,它们都继承于SettingBase。
一个ListView绑定到一个SettingBase的集合上。要添加新的Setting,可以简单地继承于SettingBase,并放到集合内。
编辑由一个ContentControl来完成,它的内容绑定到ListView的当前选择项,根据当前选择项的数据类型,使用相应的模版来提供具体的编辑界面。<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary>
<!-- 用于展现常规设置的数据模版 -->
<DataTemplate DataType="{x:Type local:GeneralSettings}">
<StackPanel>
<TextBlock Height="40" Background="PeachPuff" TextAlignment="Center" FontSize="16" Text="{Binding Name}" />
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding CanUpload}" Content="允许上传数据" />
</StackPanel>
</StackPanel>
</DataTemplate>
<!-- 用于展现编辑设置的数据模版 -->
<DataTemplate DataType="{x:Type local:EditorSettings}">
<StackPanel>
<TextBlock Height="40" Background="Wheat" TextAlignment="Center" FontSize="16" Text="{Binding Name}" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="颜色" Height="30"/>
<TextBox Text="{Binding Color}" Width="100" Height="30" Margin="12,0,0,0"/>
<Grid Background="{Binding Color}" Width="100" Height="30" />
</StackPanel>
<CheckBox IsChecked="{Binding AutoWrap}" Content="自动换行" />
</StackPanel>
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="4*" />
</Grid.ColumnDefinitions>
<ListView Name="settingList" ItemsSource="{Binding}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<!-- ContentControl的内容绑定到ListView的SelectedItem,具体的UI由DataTemplate提供-->
<ContentControl Grid.Column="1" Content="{Binding SelectedItem, ElementName=settingList}"></ContentControl>
</Grid>
</Window>
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
settings.Add(new GeneralSettings());
settings.Add(new EditorSettings());
// 这里可以添加新的设置
// settings.Add(...);
this.DataContext = settings;
}
ObservableCollection<SettingBase> settings = new ObservableCollection<SettingBase>();
} public class SettingBase : INotifyPropertyChanged
{
public virtual string Name { get; set; } public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected void FirePropertyChanged(string propertyName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
} public class GeneralSettings : SettingBase
{
public GeneralSettings()
{
this.Name = "常规设置";
} private bool canUpload;
public bool CanUpload
{
get { return canUpload; }
set { if (canUpload != value) { canUpload = value; FirePropertyChanged("CanUpload"); } }
}
} public class EditorSettings : SettingBase
{
public EditorSettings()
{
this.Name = "编辑设置";
this.Color = "#AA8844";
} private string color;
public string Color
{
get { return color; }
set { if (color != value) { color = value; FirePropertyChanged("Color"); } }
} public bool AutoWrap { get; set; }
}
}
我左侧的菜单不是采用TreeView或ListView,而是多个Expander+ListBox的形式。
而ContentControl只能绑定到其中的一个ListBox上,试了好多方法都无法实现将当前展开的Expander中的ListBox实时绑定到ContentControl中。
我左侧的菜单不是采用TreeView或ListView,而是多个Expander+ListBox的形式。
而ContentControl只能绑定到其中的一个ListBox上,试了好多方法都无法实现将当前展开的Expander中的ListBox实时绑定到ContentControl中。需要再开个贴来问吗?
{
//将ContentControl的content绑定到SettingList2这个ListBox中
Binding binding = new Binding {ElementName = "SettingList2", Path = new PropertyPath("SelectedItem")};
CcSettings.SetBinding(ContentControl.ContentProperty, binding);
} private void Expander1_Expanded_1(object sender, RoutedEventArgs e)
{
//将ContentControl的content绑定到SettingList2这个ListBox中
Binding binding = new Binding { ElementName = "SettingList1", Path = new PropertyPath("SelectedItem") };
CcSettings.SetBinding(ContentControl.ContentProperty, binding);
}