本帖最后由 aresskyaressky 于 2014-08-13 11:50:12 编辑

解决方案 »

  1.   

    这是一种典型的切换情况。
    1:WPF虽然提供了Canvas,但是它用于UIElement元素定位,并不是你再使用一个ScrollViewer,就能达到理想的效果,因为还要计算垂直的Offset。
    2: 形成平面效果,那就要修改模板,而且效果并不会太好。
    3:你自己都觉得麻烦。
    4:既然要进行保存操作,那么对保存的数据的储存就要相当的清晰。不要说什么  统一保存。把数据存放到ObservableCollection中,直至所有操作完成,就行统一的保存。个人感觉, 知道ContentControl控件的使用,会让你觉得如此简单。 把每个左侧显示的布局结构 做成用户控件,通过点击 左侧的TreeViewItem      对ContentControl 的Content属性进行设置,就可以实现切换。
    每一个UserControl 对应一个集合,最终保存再操作集合,更新到数据库或者其它文件。
    PS:个人断点,不喜勿喷。
     
      

  2.   

    比较方便的做法是采用数据绑定,并配合数据模版(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; }
        }
    }
      

  3.   

    根据你的源码,我已经实现了从左边点击ListBox的项目,右侧ContentControl加载相应的DataTemplate,因为DataTemplate的内容不能在VS或Blend中直接编辑,我就把他做成了控件引用到了DataTemplate中,现在还有一个问题。
    我左侧的菜单不是采用TreeView或ListView,而是多个Expander+ListBox的形式。
    而ContentControl只能绑定到其中的一个ListBox上,试了好多方法都无法实现将当前展开的Expander中的ListBox实时绑定到ContentControl中。
      

  4.   

    把你的方法和3楼的结合了一下,现在还有一个问题。
    我左侧的菜单不是采用TreeView或ListView,而是多个Expander+ListBox的形式。
    而ContentControl只能绑定到其中的一个ListBox上,试了好多方法都无法实现将当前展开的Expander中的ListBox实时绑定到ContentControl中。需要再开个贴来问吗?
      

  5.   

    前台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);
            }
      

  6.   

    倒是不用改变Binding。用代码可以直接设置Content。CcSettings.Content = SettlingList2.SelectedItem;