Nat*_*ium 231 c# wpf treeview selecteditem mvvm
如何检索在WPF树视图中选择的项目?我想在XAML中这样做,因为我想绑定它.
你可能会认为它SelectedItem显然是不存在的只是readonly因此无法使用.
这就是我想要做的:
<TreeView ItemsSource="{Binding Path=Model.Clusters}"
ItemTemplate="{StaticResource ClusterTemplate}"
SelectedItem="{Binding Path=Model.SelectedCluster}" />
Run Code Online (Sandbox Code Playgroud)
我想绑定SelectedItem到我的模型上的属性.
但这给了我错误:
'SelectedItem'属性是只读的,不能通过标记设置.
编辑: 好的,这是我解决这个问题的方式:
<TreeView
ItemsSource="{Binding Path=Model.Clusters}"
ItemTemplate="{StaticResource HoofdCLusterTemplate}"
SelectedItemChanged="TreeView_OnSelectedItemChanged" />
Run Code Online (Sandbox Code Playgroud)
在我的xaml的codebehindfile中:
private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
Model.SelectedCluster = (Cluster)e.NewValue;
}
Run Code Online (Sandbox Code Playgroud)
Ste*_*rex 230
我意识到这已经接受了答案,但我把它放在一起解决问题.它使用与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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以在XAML中将其用作:
<TreeView>
<e:Interaction.Behaviors>
<behaviours:BindableSelectedItemBehavior SelectedItem="{Binding SelectedItem, Mode=TwoWay}" />
</e:Interaction.Behaviors>
</TreeView>
Run Code Online (Sandbox Code Playgroud)
希望它会帮助某人!
Tho*_*que 45
此属性存在:TreeView.SelectedItem
但它只是readonly,所以你不能通过绑定分配它,只检索它
Bas*_*Bas 42
如果需要,请回答附加属性并且没有外部依赖性!
您可以创建一个可绑定的附加属性,并具有一个getter和setter:
public class TreeViewHelper
{
private static Dictionary<DependencyObject, TreeViewSelectedItemBehavior> behaviors = new Dictionary<DependencyObject, TreeViewSelectedItemBehavior>();
public static object GetSelectedItem(DependencyObject obj)
{
return (object)obj.GetValue(SelectedItemProperty);
}
public static void SetSelectedItem(DependencyObject obj, object value)
{
obj.SetValue(SelectedItemProperty, value);
}
// Using a DependencyProperty as the backing store for SelectedItem. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.RegisterAttached("SelectedItem", typeof(object), typeof(TreeViewHelper), new UIPropertyMetadata(null, SelectedItemChanged));
private static void SelectedItemChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
if (!(obj is TreeView))
return;
if (!behaviors.ContainsKey(obj))
behaviors.Add(obj, new TreeViewSelectedItemBehavior(obj as TreeView));
TreeViewSelectedItemBehavior view = behaviors[obj];
view.ChangeSelectedItem(e.NewValue);
}
private class TreeViewSelectedItemBehavior
{
TreeView view;
public TreeViewSelectedItemBehavior(TreeView view)
{
this.view = view;
view.SelectedItemChanged += (sender, e) => SetSelectedItem(view, e.NewValue);
}
internal void ChangeSelectedItem(object p)
{
TreeViewItem item = (TreeViewItem)view.ItemContainerGenerator.ContainerFromItem(p);
item.IsSelected = true;
}
}
}
Run Code Online (Sandbox Code Playgroud)
将包含该类的名称空间声明添加到XAML并按如下方式绑定(本地是我命名名称空间声明的方式):
<TreeView ItemsSource="{Binding Path=Root.Children}" local:TreeViewHelper.SelectedItem="{Binding Path=SelectedItem, Mode=TwoWay}">
</TreeView>
Run Code Online (Sandbox Code Playgroud)
现在,您可以绑定所选项目,并在视图模型中将其设置为以编程方式更改它,如果该要求出现的话.当然,这是假设您在该特定属性上实现INotifyPropertyChanged.
Del*_*lta 39
好吧,我找到了解决方案.它移动了混乱,以便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));
}
Run Code Online (Sandbox Code Playgroud)
并将其添加到您的xaml:
<local:ExtendedTreeView ItemsSource="{Binding Items}" SelectedItem_="{Binding Item, Mode=TwoWay}">
.....
</local:ExtendedTreeView>
Run Code Online (Sandbox Code Playgroud)
JiB*_*evé 22
它的答案比OP预期的要多一点......但我希望它至少可以帮助一些人.
如果你想执行ICommand每当SelectedItem改变,你可以在一个事件和使用属性的绑定命令SelectedItem中ViewModel已经不再需要.
为此:
1-添加参考 System.Windows.Interactivity
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Run Code Online (Sandbox Code Playgroud)
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>
Run Code Online (Sandbox Code Playgroud)
bst*_*ney 19
这可以通过仅使用绑定和GalaSoft MVVM Light库的EventToCommand以更好的方式完成.在您的VM中添加一个命令,该命令将在更改所选项目时调用,并初始化该命令以执行所需的任何操作.在这个例子中,我使用了一个RelayCommand,只是设置了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; }
}
Run Code Online (Sandbox Code Playgroud)
然后在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>
Run Code Online (Sandbox Code Playgroud)
Dev*_*gig 13
一切都很复杂......跟Caliburn Micro一起去(http://caliburnmicro.codeplex.com/)
视图:
<TreeView Micro:Message.Attach="[Event SelectedItemChanged] = [Action SetSelectedItem($this.SelectedItem)]" />
Run Code Online (Sandbox Code Playgroud)
视图模型:
public void SetSelectedItem(YourNodeViewModel item) {};
Run Code Online (Sandbox Code Playgroud)
我遇到了这个寻找与原作者相同答案的页面,并且证明总是有不止一种方法可以做到这一点,对我来说解决方案比到目前为止提供的答案更容易,所以我想我也不妨添加到了一堆.
绑定的动机是保持它和MVVM.ViewModel的可能用法是拥有一个带有名称的属性,例如"CurrentThingy",而在其他地方,某些其他东西上的DataContext被绑定到"CurrentThingy".
而不是通过所需的额外步骤(例如:自定义行为,第三方控件)来支持从TreeView到我的模型的良好绑定,然后从其他东西到我的模型,我的解决方案是使用简单的元素绑定另一个东西到TreeView.SelectedItem,而不是将其他东西绑定到我的ViewModel,从而跳过所需的额外工作.
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}" />
Run Code Online (Sandbox Code Playgroud)
当然,这对于阅读当前所选项目非常有用,但不能设置它,这就是我所需要的.
| 归档时间: |
|
| 查看次数: |
155927 次 |
| 最近记录: |