我要尋找一個WPF控件是TreeView和DataGrid中,像Visual Studio調試器或QuickBooks的聯繫人列表等WPF:處理編輯分層數據/的TreeView〜DataGrid的混合
上的任何其他解決方案的混合體如何處理WPF中的可編輯分層數據也將非常流行。
我要尋找一個WPF控件是TreeView和DataGrid中,像Visual Studio調試器或QuickBooks的聯繫人列表等WPF:處理編輯分層數據/的TreeView〜DataGrid的混合
上的任何其他解決方案的混合體如何處理WPF中的可編輯分層數據也將非常流行。
這在我看來就像一個相當簡單的事情,如果你正確地設計您的視圖模型來實現。
基本上,設計項目的方式與在正常數據網格中顯示它們時的方式相同,即每個項目對每個列都有一個屬性。很有可能,您的底層數據模型是分層的,但網格綁定的集合將被展平,即不管父/子關係如何,都將包含層次結構中每個節點的項目。
項目視圖模型具有一些額外的屬性:Level
,Children
,IsExpanded
,並IsVisible
。 Level
是節點祖先的計數,Children
包含子視圖模型節點,在用戶界面中使用IsExpanded
,如果節點可見,則IsVisible
爲真。它還實現了一個名爲VisibleDescendants
屬性:
public IEnumerable<NodeViewModel> VisibleDescendants
{
get
{
return Children
.Where(x => x.IsVisible)
.SelectMany(x => (new[] {x}).Concat(x.VisibleDescendants)));
}
}
您使用Level
,HasChildren
和IsExpanded
在樣式在控件的第一列的項目:他們所控制的左邊空白,什麼圖標的種類(如果有的話)顯示。
您還需要執行ExpandCommand
和CollapseCommand
屬性。如果Children.Any()
爲真且IsExpanded
爲假,則啓用ExpandCommand
,並且如果Children.Any()
爲真並且IsExpanded
爲真,則啓用CollapseCommand
。這些命令在執行時會更改IsExpanded
的值。
這就是它變得有趣的地方。實現此功能的簡單方法可能適用於您:這些項目由父視圖模型公開,該視圖模型的Items
屬性不是集合。相反,它是向下傳播子視圖模型的鏈,只產生可見的節點枚舉:
public IEnumerable<NodeViewModel> Items
{
get
{
return _Items
.Where(x => x.IsVisible)
.SelectMany(x => (new[] {x}).Concat(x.VisibleDescendants));
}
}
每當任何後代的IsVisible
屬性更改,父視圖模型提出了PropertyChanged
爲Items
財產,這迫使數據網格重新填充。
有一個不太簡單的實現過,在這裏你做出Items
屬性,實現INotifyCollectionChanged
一類,而且提高了正確CollectionChanged
活動時,子節點成爲可見/不可見,但你只想去那裏,如果性能是一個問題。
這真棒! – faztp12 2015-12-13 09:29:18
我發現最好的MVVM方法是可能與此控件:http://blogs.msdn.com/b/atc_avalon_team/archive/2006/03/01/541206.aspx
要具有層次視圖模型使用它,你可以使用分層數據模板和視圖模型指南從這裏開始: http://www.codeproject.com/Articles/24973/TreeListView
以下的答案必須從@Robert Rossney的答案開發:
public class DataGridHierarchialDataModel
{
public DataGridHierarchialDataModel() { Children = new List<DataGridHierarchialDataModel>(); }
public DataGridHierarchialDataModel Parent { get; set; }
public DataGridHierarchialData DataManager { get; set; }
public void AddChild(DataGridHierarchialDataModel t)
{
t.Parent = this;
Children.Add(t);
}
#region LEVEL
private int _level = -1;
public int Level
{
get
{
if (_level == -1)
{
_level = (Parent != null) ? Parent.Level + 1 : 0;
}
return _level;
}
}
#endregion
public bool IsExpanded
{
get { return _expanded; }
set
{
if (_expanded != value)
{
_expanded = value;
if (_expanded == true)
Expand();
else
Collapse();
}
}
}
public bool IsVisible
{
get { return _visible; }
set
{
if (_visible != value)
{
_visible = value;
if (_visible)
ShowChildren();
else
HideChildren();
}
}
}
public bool HasChildren { get { return Children.Count > 0; } }
public List<DataGridHierarchialDataModel> Children { get; set; }
public object Data { get; set; } // the Data (Specify Binding as such {Binding Data.Field})
public IEnumerable<DataGridHierarchialDataModel> VisibleDescendants
{
get
{
return Children
.Where(x => x.IsVisible)
.SelectMany(x => (new[] {x}).Concat(x.VisibleDescendants));
}
}
// Expand Collapse
private bool _expanded = false;
private bool _visible = false;
private void Collapse()
{
DataManager.RemoveChildren(this);
foreach (DataGridHierarchialDataModel d in Children)
d.IsVisible = false;
}
private void Expand()
{
DataManager.AddChildren(this);
foreach (DataGridHierarchialDataModel d in Children)
d.IsVisible = true;
}
// Only if this is Expanded
private void HideChildren()
{
if (IsExpanded)
{
// Following Order is Critical
DataManager.RemoveChildren(this);
foreach (DataGridHierarchialDataModel d in Children)
d.IsVisible = false;
}
}
private void ShowChildren()
{
if (IsExpanded)
{
// Following Order is Critical
DataManager.AddChildren(this);
foreach (DataGridHierarchialDataModel d in Children)
d.IsVisible = true;
}
}
}
public class DataGridHierarchialData : ObservableCollection<DataGridHierarchialDataModel>
{
public List<DataGridHierarchialDataModel> RawData { get; set; }
public DataGridHierarchialData() { RawData = new List<DataGridHierarchialDataModel>(); }
public void Initialize()
{
this.Clear();
foreach (DataGridHierarchialDataModel m in RawData.Where(c => c.IsVisible).SelectMany(x => new[] { x }.Concat(x.VisibleDescendants)))
{
this.Add(m);
}
}
public void AddChildren(DataGridHierarchialDataModel d)
{
if (!this.Contains(d))
return;
int parentIndex = this.IndexOf(d);
foreach (DataGridHierarchialDataModel c in d.Children)
{
parentIndex += 1;
this.Insert(parentIndex, c);
}
}
public void RemoveChildren(DataGridHierarchialDataModel d)
{
foreach (DataGridHierarchialDataModel c in d.Children)
{
if (this.Contains(c))
this.Remove(c);
}
}
}
上面類是什麼他解釋說。 使用DataGridHierarchialDataModel
中的Data
對象放置您自己的自定義數據,並生成您的等級數據並將其放入DataGridHierarchialData
的RawData
。萬一完成時致電Initialize
;
DataTable accTable = await DB.getDataTable("SELECT * FROM Fm3('l1')");
accTable.DefaultView.Sort = "iParent";
DataGridHierarchialData data = new DataGridHierarchialData();
Action<DataRowView, DataGridHierarchialDataModel> Sort = null;
Sort = new Action<DataRowView, DataGridHierarchialDataModel>((row, parent) =>
{
DataGridHierarchialDataModel t = new DataGridHierarchialDataModel() { Data = row, DataManager = data };
if (row["iGroup"].ToString() == "1")
{
foreach (DataRowView r in accTable.DefaultView.FindRows(row["iSmajId"]))
Sort(r, t);
}
parent.AddChild(t);
});
foreach (DataRowView r in accTable.DefaultView.FindRows(0))
{
DataGridHierarchialDataModel t = new DataGridHierarchialDataModel() { Data = r, DataManager = data };
if (r["iGroup"].ToString() == "1")
{
foreach (DataRowView rf in accTable.DefaultView.FindRows(r["iSmajId"]))
Sort(rf, t);
}
t.IsVisible = true; // first layer
data.RawData.Add(t);
}
data.Initialize();
dg.ItemsSource = data;
^這是我的情況下,以組帳戶
XAML:
<DataGrid x:Name="dg" AutoGenerateColumns="False" IsReadOnly="False" CanUserAddRows="False" GridLinesVisibility="All" ColumnWidth="*">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Data.sName}">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell" BasedOn="{StaticResource MetroDataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DataGridCell">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
<StackPanel Orientation="Horizontal">
<ToggleButton x:Name="Expander"
Margin="{Binding Level,Converter={StaticResource LevelToIndentConverter}}"
IsChecked="{Binding Path=IsExpanded, UpdateSourceTrigger=PropertyChanged}"
ClickMode="Press" >
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Width" Value="19"/>
<Setter Property="Height" Value="13"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Width="19" Height="13" Background="Transparent">
<Border Width="9" Height="9"
BorderThickness="0"
BorderBrush="#FF7898B5"
CornerRadius="1"
SnapsToDevicePixels="true">
<Border.Background>
<SolidColorBrush Color="Transparent"/>
<!--
<LinearGradientBrush StartPoint="0,0"
EndPoint="1,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="White"
Offset=".2"/>
<GradientStop Color="#FFC0B7A6"
Offset="1"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
-->
</Border.Background>
<Path x:Name="ExpandPath"
Data="M0,0 L0,6 L6,0 z"
Fill="Transparent"
Stroke="{DynamicResource BlackBrush}" Margin="1,2,1,1">
<Path.RenderTransform>
<RotateTransform Angle="135"
CenterY="3"
CenterX="3" />
</Path.RenderTransform>
</Path>
<!--
<Path x:Name="ExpandPath"
Margin="1,1,1,1"
Fill="Black"
Data="M 0 2 L 0 3 L 2 3 L 2 5 L 3 5 L 3 3 L 5 3 L 5 2 L 3 2 L 3 0 L 2 0 L 2 2 Z"/>
-->
</Border>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter Property="RenderTransform"
TargetName="ExpandPath">
<Setter.Value>
<RotateTransform Angle="180"
CenterY="3"
CenterX="3" />
</Setter.Value>
</Setter>
<Setter Property="Fill"
TargetName="ExpandPath"
Value="{DynamicResource GrayBrush1}" />
<Setter Property="Stroke"
TargetName="ExpandPath"
Value="{DynamicResource BlackBrush}" />
<!--
<Setter Property="Data"
TargetName="ExpandPath"
Value="M 0 2 L 0 3 L 5 3 L 5 2 Z"/>
-->
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ToggleButton.Style>
</ToggleButton>
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
Margin="{TemplateBinding Padding}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" />
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding HasChildren}" Value="False">
<Setter TargetName="Expander" Property="Visibility" Value="Hidden"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Code" Binding="{Binding Data.sCode}"/>
<DataGridTextColumn Header="Type" Binding="{Binding Data.c867x1}"/>
</DataGrid.Columns>
</DataGrid>
那大:P,但相信我,羅伯特Rossney的想法是一個爆炸:) 此外,擴展「 +',' - '樣式也包括在內(註釋掉) 希望它有幫助:)
但我想混合它與DataGrid(可編輯) – Shimmy 2010-08-11 11:07:27
+1 @Shimmy請參閱com是http://www.codeproject.com/KB/WPF/wpf_treelistview_control.aspx的一部分。它顯示瞭如何使用它,而不是一個列表視圖 – k3b 2011-03-23 14:56:45
@ k3b你應該指示這個@Hedge。我認爲這不是一個真正的問題@Shimmy關心了......只是說... – 2011-03-24 23:07:57