Kye*_*ica 31 wpf treeview mvvm
这不可能是这么困难.WPF中的TreeView不允许您设置SelectedItem,表示该属性是ReadOnly.我有TreeView填充,甚至在数据绑定集合更改时更新.
我只需要知道选择了什么项目.我正在使用MVVM,因此没有代码隐藏或变量来引用树视图.这是我找到的唯一解决方案,但它是一个明显的黑客,它在XAML中创建了另一个元素,它使用ElementName绑定将自己设置为树视图选定项,然后您必须绑定Viewmodel.关于此问题还有其他几个问题,但没有给出其他有效的解决方案.
我已经看到了这个问题,但是使用给出的答案给出了编译错误,由于某种原因,我无法将混合sdk System.Windows.Interactivity的引用添加到我的项目中.它说"未知的错误系统.窗口没有被预加载",我还没有想出如何通过它.
对于奖励积分:为什么微软会让这个元素的SelectedItem属性ReadOnly?
H.B*_*.B. 47
您不应该直接处理SelectedItem属性,绑定IsSelected到viewmodel上的属性并跟踪所选项目.
草图:
<TreeView ItemsSource="{Binding TreeData}">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
Run Code Online (Sandbox Code Playgroud)
public class TViewModel : INotifyPropertyChanged
{
private static object _selectedItem = null;
// This is public get-only here but you could implement a public setter which
// also selects the item.
// Also this should be moved to an instance property on a VM for the whole tree,
// otherwise there will be conflicts for more than one tree.
public static object SelectedItem
{
get { return _selectedItem; }
private set
{
if (_selectedItem != value)
{
_selectedItem = value;
OnSelectedItemChanged();
}
}
}
static virtual void OnSelectedItemChanged()
{
// Raise event / do other things
}
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
if (_isSelected != value)
{
_isSelected = value;
OnPropertyChanged("IsSelected");
if (_isSelected)
{
SelectedItem = this;
}
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = this.PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Run Code Online (Sandbox Code Playgroud)
Bas*_*Bas 12
您可以创建一个可绑定的附加属性,并具有一个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}"/>
Run Code Online (Sandbox Code Playgroud)
现在,您可以绑定所选项目,并在视图模型中将其设置为以编程方式更改它,如果该要求出现的话.当然,这是假设您在该特定属性上实现INotifyPropertyChanged.
以MVVM可接受的方式解决此问题的一种非常不寻常但非常有效的方法如下:
SelectedSomethingviewmodel中的某个属性.这个ContentControl将"保持"所选对象并处理它的绑定,OneWayToSource;SelectedItemChanged在TreeView中收听,并在代码隐藏中添加一个处理程序,将ContentControl.Content设置为新选择的项目.XAML:
<ContentControl x:Name="SelectedItemHelper" Content="{Binding SelectedObject, Mode=OneWayToSource}" Visibility="Collapsed"/>
<TreeView ItemsSource="{Binding SomeCollection}"
SelectedItemChanged="TreeView_SelectedItemChanged">
Run Code Online (Sandbox Code Playgroud)
代码背后:
private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
SelectedItemHelper.Content = e.NewValue;
}
Run Code Online (Sandbox Code Playgroud)
视图模型:
public object SelectedObject // Class is not actually "object"
{
get { return _selected_object; }
set
{
_selected_object = value;
RaisePropertyChanged(() => SelectedObject);
Console.WriteLine(SelectedObject);
}
}
object _selected_object;
Run Code Online (Sandbox Code Playgroud)
使用这不起作用。见编辑。OneWayToSource绑定模式。
编辑:根据这个问题,看起来这是微软的一个错误或“设计使然”行为;不过,已经发布了一些解决方法。这些对您的 TreeView 有用吗?
Microsoft Connect 问题:https : //connect.microsoft.com/WPF/feedback/details/523865/read-only-dependency-properties-does-not-support-onewaytosource-bindings
Microsoft 于 2010 年 1 月 10 日下午 2:46 发布
我们今天不能在 WPF 中这样做,出于同样的原因,我们不能支持对不是 DependencyProperties 的属性的绑定。绑定的运行时每个实例状态保存在 BindingExpression 中,我们将其存储在目标 DependencyObject 的 EffectiveValueTable 中。当目标属性不是 DP 或 DP 是只读的时,就没有地方存储 BindingExpression。
有可能有一天我们会选择将绑定功能扩展到这两种情况。我们经常被问到他们。换句话说,您的请求已经在我们未来版本中要考虑的功能列表中。
感谢您的反馈意见。
| 归档时间: |
|
| 查看次数: |
60420 次 |
| 最近记录: |