선택한 데이터 바인딩WPF 트리 보기의 항목
WPF 트리 보기에서 선택한 항목을 검색하려면 어떻게 해야 합니까?저는 이것을 XAML에서 하고 싶습니다. 왜냐하면 제가 그것을 묶고 싶기 때문입니다.
이 생다고지있도습다니실각하그렇▁that다▁it라고 생각할지도 모릅니다.SelectedItem하지만 분명히 존재하지 않는 것은 읽기 전용이므로 사용할 수 없습니다.
이것이 바로 제가 하고 싶은 일입니다.
<TreeView ItemsSource="{Binding Path=Model.Clusters}"
ItemTemplate="{StaticResource ClusterTemplate}"
SelectedItem="{Binding Path=Model.SelectedCluster}" />
나는 그것을 묶고 싶습니다.SelectedItem내 모델에 있는 부동산으로.
하지만 이것은 나에게 오류를 줍니다.
'선택됨Item' 속성이 읽기 전용이므로 마크업에서 설정할 수 없습니다.
편집: 자, 이것이 제가 해결한 방법입니다.
<TreeView
ItemsSource="{Binding Path=Model.Clusters}"
ItemTemplate="{StaticResource HoofdCLusterTemplate}"
SelectedItemChanged="TreeView_OnSelectedItemChanged" />
그리고 내 xaml의 비밀번호 파일에서:
private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
Model.SelectedCluster = (Cluster)e.NewValue;
}
저는 이것이 이미 받아들여진 답이라는 것을 알고 있지만, 저는 문제를 해결하기 위해 이것을 정리했습니다.Delta의 솔루션과 유사한 아이디어를 사용하지만 TreeView를 하위 분류할 필요는 없습니다.
public class BindableSelectedItemBehavior : Behavior<TreeView>
{
#region SelectedItem Property
public object SelectedItem
{
get { return (object)GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
public static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.Register("SelectedItem", typeof(object), typeof(BindableSelectedItemBehavior), new UIPropertyMetadata(null, OnSelectedItemChanged));
private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var item = e.NewValue as TreeViewItem;
if (item != null)
{
item.SetValue(TreeViewItem.IsSelectedProperty, true);
}
}
#endregion
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.SelectedItemChanged += OnTreeViewSelectedItemChanged;
}
protected override void OnDetaching()
{
base.OnDetaching();
if (this.AssociatedObject != null)
{
this.AssociatedObject.SelectedItemChanged -= OnTreeViewSelectedItemChanged;
}
}
private void OnTreeViewSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
this.SelectedItem = e.NewValue;
}
}
그런 다음 XAML에서 다음과 같이 사용할 수 있습니다.
<TreeView>
<e:Interaction.Behaviors>
<behaviours:BindableSelectedItemBehavior SelectedItem="{Binding SelectedItem, Mode=TwoWay}" />
</e:Interaction.Behaviors>
</TreeView>
바라건대 그것이 누군가를 도울 것입니다!
그러나 읽기 전용이므로 바인딩을 통해 할당할 수 없으며 검색만 수행합니다.
해결책을 찾았어요MVVM이 작동하도록 엉망진창으로 이동합니다.
먼저 이 클래스를 추가합니다.
public class ExtendedTreeView : TreeView
{
public ExtendedTreeView()
: base()
{
this.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(___ICH);
}
void ___ICH(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (SelectedItem != null)
{
SetValue(SelectedItem_Property, SelectedItem);
}
}
public object SelectedItem_
{
get { return (object)GetValue(SelectedItem_Property); }
set { SetValue(SelectedItem_Property, value); }
}
public static readonly DependencyProperty SelectedItem_Property = DependencyProperty.Register("SelectedItem_", typeof(object), typeof(ExtendedTreeView), new UIPropertyMetadata(null));
}
그리고 이것을 당신의 xaml에 추가합니다.
<local:ExtendedTreeView ItemsSource="{Binding Items}" SelectedItem_="{Binding Item, Mode=TwoWay}">
.....
</local:ExtendedTreeView>
OP가 예상한 것보다 조금 더 많은 답변을 해줍니다.하지만 적어도 누군가에게 도움이 되길 바랍니다.
이 경우는려를 .ICommand언제든지SelectedItem 및 수 . 속성은 " " " " " " 입니다.SelectedItem에 시대에ViewModel더 이상 필요하지 않습니다.
수행 방법:
1 - 다음에 참조 추가합니다.System.Windows.Interactivity
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
. 2 - 명령이바인합니다딩에벤트을▁2다.SelectedItemChanged
<TreeView x:Name="myTreeView" Margin="1"
ItemsSource="{Binding Directories}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<i:InvokeCommandAction Command="{Binding SomeCommand}"
CommandParameter="
{Binding ElementName=myTreeView
,Path=SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<TreeView.ItemTemplate>
<!-- ... -->
</TreeView.ItemTemplate>
</TreeView>
바인딩과 GalaSoft MVVM Light 라이브러리의 EventToCommand만을 사용하여 '더 나은' 방식으로 이 작업을 수행할 수 있습니다.선택한 항목이 변경될 때 호출될 명령을 VM에 추가하고 필요한 작업을 수행하도록 명령을 초기화합니다.이 예에서는 릴레이 명령을 사용했으며 SelectedCluster 속성만 설정합니다.
public class ViewModel
{
public ViewModel()
{
SelectedClusterChanged = new RelayCommand<Cluster>( c => SelectedCluster = c );
}
public RelayCommand<Cluster> SelectedClusterChanged { get; private set; }
public Cluster SelectedCluster { get; private set; }
}
그런 다음 xaml에 EventToCommand 동작을 추가합니다.이것은 블렌드를 사용하면 정말 쉽습니다.
<TreeView
x:Name="lstClusters"
ItemsSource="{Binding Path=Model.Clusters}"
ItemTemplate="{StaticResource HoofdCLusterTemplate}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding SelectedClusterChanged}" CommandParameter="{Binding ElementName=lstClusters,Path=SelectedValue}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
모두 복잡한...Caliburn Micro(http://caliburnmicro.codeplex.com/) 로 이동합니다.
보기:
<TreeView Micro:Message.Attach="[Event SelectedItemChanged] = [Action SetSelectedItem($this.SelectedItem)]" />
모델 보기:
public void SetSelectedItem(YourNodeViewModel item) {};
저는 이 페이지에서 원작자와 동일한 답을 찾았고, 그것을 하는 방법이 항상 하나 이상이라는 것을 증명했습니다. 저를 위한 해결책은 지금까지 여기에 제공된 답보다 훨씬 쉬웠기 때문에, 저는 제가 더 많은 것을 추가하는 것이 낫다고 생각했습니다.
바인딩의 동기는 잘 유지하고 MVVM을 유지하는 것입니다.ViewModel은 "현재"와 같은 이름을 가진 속성을 사용할 수 있습니다.Thingy", 그리고 다른 곳에서, 다른 것의 DataContext는 "현재"로 묶여 있습니다.'싱키'.
TreeView에서 My Model로의 멋진 바인딩을 지원하는 데 필요한 추가 단계(예: 사용자 지정 동작, 타사 제어)를 거치는 대신 다른 것에서 My Model로의 바인딩을 지원하는 간단한 Element를 사용하여 다른 것을 TreeView로 바인딩하는 것이 해결책이었습니다.선택된다른 항목을 내 View Model에 바인딩하는 대신 추가 작업을 건너뜁니다.
XAML:
<TreeView x:Name="myTreeView" ItemsSource="{Binding MyThingyCollection}">
.... stuff
</TreeView>
<!-- then.. somewhere else where I want to see the currently selected TreeView item: -->
<local:MyThingyDetailsView
DataContext="{Binding ElementName=myTreeView, Path=SelectedItem}" />
물론 이것은 현재 선택된 항목을 읽기에는 좋지만 설정하지 않으면 됩니다.
TreeViewItem을 사용할 수도 있습니다.IsSelected 속성
제 요구 사항은 TreeView가 필요하고 바인딩된 개체가 Collection<> 유형이므로 계층적 데이터 템플릿이 필요한 PRISM-MVVM 기반 솔루션이었습니다.기본 BindableSelectedItemBehavior는 하위 TreeViewItem을 식별할 수 없습니다.이 시나리오에서 작동하도록 만드는 것.
public class BindableSelectedItemBehavior : Behavior<TreeView>
{
#region SelectedItem Property
public object SelectedItem
{
get { return (object)GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
public static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.Register("SelectedItem", typeof(object), typeof(BindableSelectedItemBehavior), new UIPropertyMetadata(null, OnSelectedItemChanged));
private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var behavior = sender as BindableSelectedItemBehavior;
if (behavior == null) return;
var tree = behavior.AssociatedObject;
if (tree == null) return;
if (e.NewValue == null)
foreach (var item in tree.Items.OfType<TreeViewItem>())
item.SetValue(TreeViewItem.IsSelectedProperty, false);
var treeViewItem = e.NewValue as TreeViewItem;
if (treeViewItem != null)
treeViewItem.SetValue(TreeViewItem.IsSelectedProperty, true);
else
{
var itemsHostProperty = tree.GetType().GetProperty("ItemsHost", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (itemsHostProperty == null) return;
var itemsHost = itemsHostProperty.GetValue(tree, null) as Panel;
if (itemsHost == null) return;
foreach (var item in itemsHost.Children.OfType<TreeViewItem>())
{
if (WalkTreeViewItem(item, e.NewValue))
break;
}
}
}
public static bool WalkTreeViewItem(TreeViewItem treeViewItem, object selectedValue)
{
if (treeViewItem.DataContext == selectedValue)
{
treeViewItem.SetValue(TreeViewItem.IsSelectedProperty, true);
treeViewItem.Focus();
return true;
}
var itemsHostProperty = treeViewItem.GetType().GetProperty("ItemsHost", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (itemsHostProperty == null) return false;
var itemsHost = itemsHostProperty.GetValue(treeViewItem, null) as Panel;
if (itemsHost == null) return false;
foreach (var item in itemsHost.Children.OfType<TreeViewItem>())
{
if (WalkTreeViewItem(item, selectedValue))
break;
}
return false;
}
#endregion
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.SelectedItemChanged += OnTreeViewSelectedItemChanged;
}
protected override void OnDetaching()
{
base.OnDetaching();
if (this.AssociatedObject != null)
{
this.AssociatedObject.SelectedItemChanged -= OnTreeViewSelectedItemChanged;
}
}
private void OnTreeViewSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
this.SelectedItem = e.NewValue;
}
}
이를 통해 레벨에 관계없이 모든 요소를 반복할 수 있습니다.
저는 스티브 그레이트렉스가 제공한 행동에 추가할 것을 제안합니다.TreeView 컬렉션이 아닐 수 있으므로 소스의 변경 내용을 반영하지 않습니다.아이템. 그래서 트리뷰를 찾는 것이 문제입니다.데이터 컨텍스트가 원본에서 선택한 값인 트리의 항목입니다.TreeView에는 TreeView를 보유한 "ItemsHost"라는 보호된 속성이 있습니다.항목 컬렉션입니다.우리는 그것을 반사를 통해 얻을 수 있고 선택한 아이템을 찾기 위해 트리를 걸을 수 있습니다.
private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var behavior = sender as BindableSelectedItemBehaviour;
if (behavior == null) return;
var tree = behavior.AssociatedObject;
if (tree == null) return;
if (e.NewValue == null)
foreach (var item in tree.Items.OfType<TreeViewItem>())
item.SetValue(TreeViewItem.IsSelectedProperty, false);
var treeViewItem = e.NewValue as TreeViewItem;
if (treeViewItem != null)
{
treeViewItem.SetValue(TreeViewItem.IsSelectedProperty, true);
}
else
{
var itemsHostProperty = tree.GetType().GetProperty("ItemsHost", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (itemsHostProperty == null) return;
var itemsHost = itemsHostProperty.GetValue(tree, null) as Panel;
if (itemsHost == null) return;
foreach (var item in itemsHost.Children.OfType<TreeViewItem>())
if (WalkTreeViewItem(item, e.NewValue)) break;
}
}
public static bool WalkTreeViewItem(TreeViewItem treeViewItem, object selectedValue) {
if (treeViewItem.DataContext == selectedValue)
{
treeViewItem.SetValue(TreeViewItem.IsSelectedProperty, true);
treeViewItem.Focus();
return true;
}
foreach (var item in treeViewItem.Items.OfType<TreeViewItem>())
if (WalkTreeViewItem(item, selectedValue)) return true;
return false;
}
이러한 방식으로 양방향 바인딩에 대해 동작이 작동합니다.또는 항목을 이동할 수 있습니다.호스트 획득을 Behavior's OnAttached 메서드로 수행하여 바인딩이 업데이트될 때마다 반사를 사용하는 오버헤드를 줄입니다.
XAML 바인딩 가능 선택됨을 생성하는 방법도 있습니다.상호 작용을 사용하지 않는 항목 속성입니다.행동.
public static class BindableSelectedItemHelper
{
#region Properties
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.RegisterAttached("SelectedItem", typeof(object), typeof(BindableSelectedItemHelper),
new FrameworkPropertyMetadata(null, OnSelectedItemPropertyChanged));
public static readonly DependencyProperty AttachProperty = DependencyProperty.RegisterAttached("Attach", typeof(bool), typeof(BindableSelectedItemHelper), new PropertyMetadata(false, Attach));
private static readonly DependencyProperty IsUpdatingProperty = DependencyProperty.RegisterAttached("IsUpdating", typeof(bool), typeof(BindableSelectedItemHelper));
#endregion
#region Implementation
public static void SetAttach(DependencyObject dp, bool value)
{
dp.SetValue(AttachProperty, value);
}
public static bool GetAttach(DependencyObject dp)
{
return (bool)dp.GetValue(AttachProperty);
}
public static string GetSelectedItem(DependencyObject dp)
{
return (string)dp.GetValue(SelectedItemProperty);
}
public static void SetSelectedItem(DependencyObject dp, object value)
{
dp.SetValue(SelectedItemProperty, value);
}
private static bool GetIsUpdating(DependencyObject dp)
{
return (bool)dp.GetValue(IsUpdatingProperty);
}
private static void SetIsUpdating(DependencyObject dp, bool value)
{
dp.SetValue(IsUpdatingProperty, value);
}
private static void Attach(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
TreeListView treeListView = sender as TreeListView;
if (treeListView != null)
{
if ((bool)e.OldValue)
treeListView.SelectedItemChanged -= SelectedItemChanged;
if ((bool)e.NewValue)
treeListView.SelectedItemChanged += SelectedItemChanged;
}
}
private static void OnSelectedItemPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
TreeListView treeListView = sender as TreeListView;
if (treeListView != null)
{
treeListView.SelectedItemChanged -= SelectedItemChanged;
if (!(bool)GetIsUpdating(treeListView))
{
foreach (TreeViewItem item in treeListView.Items)
{
if (item == e.NewValue)
{
item.IsSelected = true;
break;
}
else
item.IsSelected = false;
}
}
treeListView.SelectedItemChanged += SelectedItemChanged;
}
}
private static void SelectedItemChanged(object sender, RoutedEventArgs e)
{
TreeListView treeListView = sender as TreeListView;
if (treeListView != null)
{
SetIsUpdating(treeListView, true);
SetSelectedItem(treeListView, treeListView.SelectedItem);
SetIsUpdating(treeListView, false);
}
}
#endregion
}
그런 다음 XAML에서 다음과 같이 사용할 수 있습니다.
<TreeView helper:BindableSelectedItemHelper.Attach="True"
helper:BindableSelectedItemHelper.SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
저는 이 질문에 대한 모든 해결책을 시도했습니다.아무도 내 문제를 완벽하게 해결하지 못했습니다.따라서 이러한 상속된 클래스는 재정의된 속성 SelectedItem과 함께 사용하는 것이 좋다고 생각합니다.GUI에서 트리 요소를 선택하고 코드에서 이 속성 값을 설정하면 완벽하게 작동합니다.
public class TreeViewEx : TreeView
{
public TreeViewEx()
{
this.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(TreeViewEx_SelectedItemChanged);
}
void TreeViewEx_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
this.SelectedItem = e.NewValue;
}
#region SelectedItem
/// <summary>
/// Gets or Sets the SelectedItem possible Value of the TreeViewItem object.
/// </summary>
public new object SelectedItem
{
get { return this.GetValue(TreeViewEx.SelectedItemProperty); }
set { this.SetValue(TreeViewEx.SelectedItemProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public new static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.Register("SelectedItem", typeof(object), typeof(TreeViewEx),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, SelectedItemProperty_Changed));
static void SelectedItemProperty_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
TreeViewEx targetObject = dependencyObject as TreeViewEx;
if (targetObject != null)
{
TreeViewItem tvi = targetObject.FindItemNode(targetObject.SelectedItem) as TreeViewItem;
if (tvi != null)
tvi.IsSelected = true;
}
}
#endregion SelectedItem
public TreeViewItem FindItemNode(object item)
{
TreeViewItem node = null;
foreach (object data in this.Items)
{
node = this.ItemContainerGenerator.ContainerFromItem(data) as TreeViewItem;
if (node != null)
{
if (data == item)
break;
node = FindItemNodeInChildren(node, item);
if (node != null)
break;
}
}
return node;
}
protected TreeViewItem FindItemNodeInChildren(TreeViewItem parent, object item)
{
TreeViewItem node = null;
bool isExpanded = parent.IsExpanded;
if (!isExpanded) //Can't find child container unless the parent node is Expanded once
{
parent.IsExpanded = true;
parent.UpdateLayout();
}
foreach (object data in parent.Items)
{
node = parent.ItemContainerGenerator.ContainerFromItem(data) as TreeViewItem;
if (data == item && node != null)
break;
node = FindItemNodeInChildren(node, item);
if (node != null)
break;
}
if (node == null && parent.IsExpanded != isExpanded)
parent.IsExpanded = isExpanded;
if (node != null)
parent.IsExpanded = true;
return node;
}
}
더 나은 답변이지만 선택 항목을 가져오거나 설정하는 방법에 대해서는 언급하지 않았습니다.View Model의 항목입니다.
- IsSelected 부울 속성을 ItemViewModel에 추가하고 TreeViewItem의 StyleSetter에서 바인딩합니다.
- 선택한 항목 추가TreeView의 데이터 컨텍스트로 사용되는 ViewModel에 대한 항목 속성입니다.위 솔루션에서 누락된 부분입니다.
항목 VM... 공용 속성이 부울로 선택됨얻다반환 _func.선택한 노드는 나입니다.종료 Get설정(값을 부울 값으로 지정)IsSelected 값인 경우_func.SelectedNode = If(값, Me, Nothing)종료할 경우속성 변경 상승()끝 집합끝 특성트리 VM... 공용 속성 선택됨Item As ItemVM얻다반송 _선택됨항목종료 Get설정(항목으로 값 설정)VM)_선택된 경우항목이 값인 경우돌아가다종료할 경우Dim prev = _선택됨항목_선택된항목 = 값만약 이전이 아무것도 아니라면 그때.앞의선택 여부 = 거짓종료할 경우_선택된 경우그러면 항목은 아무것도 아닙니다._selectedItem.선택 여부 = 참종료할 경우끝 집합끝 특성
<TreeView ItemsSource="{Binding Path=TreeVM}"
BorderBrush="Transparent">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding IsExpanded}"/>
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
하루 동안 인터넷을 공부한 후 일반 WPF/C# 환경에서 일반 트리 보기를 만든 후 항목을 선택할 수 있는 나만의 해결책을 찾았습니다.
private void BuildSortTree(int sel)
{
MergeSort.Items.Clear();
TreeViewItem itTemp = new TreeViewItem();
itTemp.Header = SortList[0];
MergeSort.Items.Add(itTemp);
TreeViewItem prev;
itTemp.IsExpanded = true;
if (0 == sel) itTemp.IsSelected= true;
prev = itTemp;
for(int i = 1; i<SortList.Count; i++)
{
TreeViewItem itTempNEW = new TreeViewItem();
itTempNEW.Header = SortList[i];
prev.Items.Add(itTempNEW);
itTempNEW.IsExpanded = true;
if (i == sel) itTempNEW.IsSelected = true;
prev = itTempNEW ;
}
}
TreeView 항목의 IsSelected 속성을 사용하여 수행할 수도 있습니다.제가 처리한 방법은 이렇습니다.
public delegate void TreeviewItemSelectedHandler(TreeViewItem item);
public class TreeViewItem
{
public static event TreeviewItemSelectedHandler OnItemSelected = delegate { };
public bool IsSelected
{
get { return isSelected; }
set
{
isSelected = value;
if (value)
OnItemSelected(this);
}
}
}
그런 다음 TreeView가 바인딩된 데이터가 포함된 ViewModel에서 TreeView에서 이벤트를 구독하면 됩니다.항목 클래스.
TreeViewItem.OnItemSelected += TreeViewItemSelected;
그리고 마지막으로 이 핸들러를 동일한 View Model에 구현합니다.
private void TreeViewItemSelected(TreeViewItem item)
{
//Do something
}
물론 구속력은
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
이 스레드가 10년 된 것은 알지만 문제는 여전히 존재합니다.
원래 질문은 선택한 항목을 '검색'하는 것이었습니다.또한 선택한 항목을 내 뷰 모델에서 "취득"해야 했습니다(설정하지 않음).이 스레드의 모든 답변 중에서 문제에 다르게 접근하는 것은 'Wes'의 답변뿐입니다.'선택한 항목'을 데이터 바인딩의 대상으로 사용할 수 있는 경우 데이터 바인딩의 소스로 사용합니다.다른 뷰 특성에 대해 수행했습니다. 뷰 모델 특성에 대해 수행합니다.
우리는 두 가지가 필요합니다.
- 뷰 모델에 종속성 속성 생성(내 트리 뷰가 'MyObject' 유형의 개체에 바인딩되어 있는 'MyObject' 유형의 경우)
- 트리 보기에서 바인딩합니다.선택된View 생성자의 이 속성에 대한 항목(예, 코드 뒤에 있지만 데이터 컨텍스트도 여기서 초기화할 가능성이 높습니다.)
모델 보기:
public static readonly DependencyProperty SelectedTreeViewItemProperty = DependencyProperty.Register("SelectedTreeViewItem", typeof(MyObject), typeof(MyViewModel), new PropertyMetadata(OnSelectedTreeViewItemChanged));
private static void OnSelectedTreeViewItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as MyViewModel).OnSelectedTreeViewItemChanged(e);
}
private void OnSelectedTreeViewItemChanged(DependencyPropertyChangedEventArgs e)
{
//do your stuff here
}
public MyObject SelectedWorkOrderTreeViewItem
{
get { return (MyObject)GetValue(SelectedTreeViewItemProperty); }
set { SetValue(SelectedTreeViewItemProperty, value); }
}
생성자 보기:
Binding binding = new Binding("SelectedItem")
{
Source = treeView, //name of tree view in xaml
Mode = BindingMode.OneWay
};
BindingOperations.SetBinding(DataContext, MyViewModel.SelectedTreeViewItemProperty, binding);
View 모델의 선택한 항목을 View의 선택한 항목에서 업데이트하는 데 완벽하게 작동하는 이 솔루션(가장 쉽고 메모리 누수가 없는 솔루션)을 제안합니다.
보기 모델에서 선택한 항목을 변경하면 보기의 선택한 항목이 업데이트되지 않습니다.
public class TreeViewEx : TreeView
{
public static readonly DependencyProperty SelectedItemExProperty = DependencyProperty.Register("SelectedItemEx", typeof(object), typeof(TreeViewEx), new FrameworkPropertyMetadata(default(object))
{
BindsTwoWayByDefault = true // Required in order to avoid setting the "BindingMode" from the XAML
});
public object SelectedItemEx
{
get => GetValue(SelectedItemExProperty);
set => SetValue(SelectedItemExProperty, value);
}
protected override void OnSelectedItemChanged(RoutedPropertyChangedEventArgs<object> e)
{
SelectedItemEx = e.NewValue;
}
}
XAML 사용
<l:TreeViewEx ItemsSource="{Binding Path=Items}" SelectedItemEx="{Binding Path=SelectedItem}" >
(TreeView가 이 문제와 관련하여 명백하게 결함이 있다는 것에 모두 동의합니다.선택한 항목에 바인딩항목은 분명했을 것입니다.한숨)
TreeView의 IsSelected 속성과 올바르게 상호 작용할 솔루션이 필요했습니다.아이템, 제가 한 방법은 다음과 같습니다.
// the Type CustomThing needs to implement IsSelected with notification
// for this to work.
public class CustomTreeView : TreeView
{
public CustomThing SelectedCustomThing
{
get
{
return (CustomThing)GetValue(SelectedNode_Property);
}
set
{
SetValue(SelectedNode_Property, value);
if(value != null) value.IsSelected = true;
}
}
public static DependencyProperty SelectedNode_Property =
DependencyProperty.Register(
"SelectedCustomThing",
typeof(CustomThing),
typeof(CustomTreeView),
new FrameworkPropertyMetadata(
null,
FrameworkPropertyMetadataOptions.None,
SelectedNodeChanged));
public CustomTreeView(): base()
{
this.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(SelectedItemChanged_CustomHandler);
}
void SelectedItemChanged_CustomHandler(object sender, RoutedPropertyChangedEventArgs<object> e)
{
SetValue(SelectedNode_Property, SelectedItem);
}
private static void SelectedNodeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var treeView = d as CustomTreeView;
var newNode = e.NewValue as CustomThing;
treeView.SelectedCustomThing = (CustomThing)e.NewValue;
}
}
이 XAML을 사용하는 경우:
<local:CustonTreeView ItemsSource="{Binding TreeRoot}"
SelectedCustomThing="{Binding SelectedNode,Mode=TwoWay}">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
</Style>
</TreeView.ItemContainerStyle>
</local:CustonTreeView>
다음과 같은 기능을 제공하는 솔루션을 제공합니다.
2방향 바인딩 지원
TreeViewItem을 자동으로 업데이트합니다.IsSelected 속성(SelectedItem에 따라)
TreeView 하위 분류 없음
ViewModel에 바인딩된 항목은 모든 유형(null인 경우도 있음)일 수 있습니다.
1/ CS에 다음 코드를 붙여넣습니다.
public class BindableSelectedItem
{
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.RegisterAttached(
"SelectedItem", typeof(object), typeof(BindableSelectedItem), new PropertyMetadata(default(object), OnSelectedItemPropertyChangedCallback));
private static void OnSelectedItemPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var treeView = d as TreeView;
if (treeView != null)
{
BrowseTreeViewItems(treeView, tvi =>
{
tvi.IsSelected = tvi.DataContext == e.NewValue;
});
}
else
{
throw new Exception("Attached property supports only TreeView");
}
}
public static void SetSelectedItem(DependencyObject element, object value)
{
element.SetValue(SelectedItemProperty, value);
}
public static object GetSelectedItem(DependencyObject element)
{
return element.GetValue(SelectedItemProperty);
}
public static void BrowseTreeViewItems(TreeView treeView, Action<TreeViewItem> onBrowsedTreeViewItem)
{
var collectionsToVisit = new System.Collections.Generic.List<Tuple<ItemContainerGenerator, ItemCollection>> { new Tuple<ItemContainerGenerator, ItemCollection>(treeView.ItemContainerGenerator, treeView.Items) };
var collectionIndex = 0;
while (collectionIndex < collectionsToVisit.Count)
{
var itemContainerGenerator = collectionsToVisit[collectionIndex].Item1;
var itemCollection = collectionsToVisit[collectionIndex].Item2;
for (var i = 0; i < itemCollection.Count; i++)
{
var tvi = itemContainerGenerator.ContainerFromIndex(i) as TreeViewItem;
if (tvi == null)
{
continue;
}
if (tvi.ItemContainerGenerator.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
{
collectionsToVisit.Add(new Tuple<ItemContainerGenerator, ItemCollection>(tvi.ItemContainerGenerator, tvi.Items));
}
onBrowsedTreeViewItem(tvi);
}
collectionIndex++;
}
}
}
2/ XAML 파일의 사용 예
<TreeView myNS:BindableSelectedItem.SelectedItem="{Binding Path=SelectedItem, Mode=TwoWay}" />
일부 항목 목록을 클릭하면 "선택됨" 속성에 데이터가 표시됩니다.
모델 보기:
public class ShellViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
private ObservableCollection<Books> _books;
private List<Books> bookList = new List<Books>();
public ObservableCollection<Books> Books
{
get { return _books; }
set { _books = value; NotifyPropertyChanged("Books"); }
}
private Books books;
public Books Selected
{
get { return books; }
set { books = value; }
}
public ShellViewModel()
{
bookList = new List<Books>()
{
new Books{BookName = "Harry Poter",Price ="15$"},
new Books{BookName = "Harry Poter 2 ",Price ="14.95$"},
new Books{BookName = "Harry Poter 3",Price ="18.50$"},
new Books{BookName = "Harry Poter 4",Price ="32.90$"},
};
Books = new ObservableCollection<Books>(bookList);
}
}
public class Books
{
public string BookName { get; set; }
public string Price { get; set; }
}
XAML:
<ListView x:Name="lst" Grid.Row="2" ItemsSource="{Binding Books}" SelectedItem="{Binding Selected}">
<ListView.View>
<GridView >
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding BookName}" />
<GridViewColumn Header="Price" Width="100" DisplayMemberBinding="{Binding Price}"/>
</GridView>
</ListView.View>
</ListView>
저는 이것이 게시된 지 오래되었다는 것을 알지만, FWIW 저는 텔리크의 RadTreeView를 사용하고 있고, 선택되었습니다.그 동안 문제가 해결되었거나 텔레릭이 해결해 주었습니다.
언급URL : https://stackoverflow.com/questions/1000040/data-binding-to-selecteditem-in-a-wpf-treeview
'programing' 카테고리의 다른 글
| 이클립스를 사용한 Tomcat 원격 디버깅 (0) | 2023.04.27 |
|---|---|
| 반복기, 목록 보기, 데이터 목록, 데이터 그리드, 그리드 보기...어떤 걸 고를까요? (0) | 2023.04.27 |
| Azure의 무료 SQL Server (0) | 2023.04.27 |
| 이클립스의 Android Device Chooser가 내 Android 장치를 표시하지 않는 이유는 무엇입니까? (0) | 2023.04.27 |
| Git 상태 줄 끝 무시 / 동일한 파일 / Windows & Linux 환경 / 드롭박스 / mold (0) | 2023.04.27 |