如何在一个视图模型上绑定一些控件

时间:2012-08-24 11:18:33

标签: wpf

我有一些带有一些字段的视图模型,即

type ViewModel =
    member x.a = [1;2;3]
    member x.b = [4;5;6]
    member x.c = [7]

并在WPF应用程序中放置一些视图,如:

<Control.Resources>
                    <DataTemplate x:Key="ItemTempl">
                        <TextBlock Text="{Binding}" />
                    </DataTemplate>

                    <DataTemplate x:Key="SomeTempl">
                        <ListBox ItemsSource="{Binding}"
                                 ItemTemplate="{StaticResource ItemTempl}" />
                    </DataTemplate>
                </Control.Resources>

                <StackPanel>
                    <TabControl x:Name="ListBoxViewPresenter">
                        <TabItem Header="vm.a" Content="{Binding vm.a}" 
                             ContentTemplate="{StaticResource SomeTempl}"/>
                        <TabItem Header="vm.b" Content="{Binding vm.b}" 
                             ContentTemplate="{StaticResource SomeTempl}"/>
                        <TabItem Header="vm.c" Content="{Binding vm.c}" 
                             ContentTemplate="{StaticResource SomeTempl}"/>
                    </TabControl>
                    <ListBox x:Name="ListBoxViewPresenter">
                        <ListBoxItem Content="{Binding vm.a}" 
                                     ContentTemplate="{StaticResource SomeTempl}" />
                        <ListBoxItem Content="{Binding vm.b}" 
                                     ContentTemplate="{StaticResource SomeTempl}" />
                        <ListBoxItem Content="{Binding vm.c}" 
                                     ContentTemplate="{StaticResource SomeTempl}" />
                    </ListBox>
                </StackPanel>

我应该怎样做才能实现这样的行为: 当您在ListBoxViewPresenter中单击vm.a / b / c中的某个元素时,必须在相应的TabItem中选择ListBoxViewPresenter中的相同元素。

UPD: 特别是我的真正问题,从原始主题改变。

我有ViewModel的字段:onelines,twolines ......和名为selected_scheme的字段。 在xaml:

<TreeViewItem Header="{Binding Path=name}" x:Name="ProjectArea">
                    <TreeViewItem Header="Однониточные планы" Style="{StaticResource MyTreeViewItem}">
                        <ContentPresenter Content="{Binding onelines}" ContentTemplate="{StaticResource SchemeWrapperTemplate}" />
                    </TreeViewItem>
                    <TreeViewItem Header="Двухниточные планы" Style="{StaticResource MyTreeViewItem}">
                        <ContentPresenter Content="{Binding twolines}" ContentTemplate="{StaticResource SchemeWrapperTemplate}" />
                    </TreeViewItem>

数据模板:

            <DataTemplate x:Key="SchemeWrapperTemplate">
            <ListBox ItemsSource="{Binding schemes}" 
                     ItemTemplate="{StaticResource SchemeTemplate}"
                     SelectedItem="{Binding selected_scheme}">
                <ListBox.Style>

在该计划的其他地方:

 <Grid Grid.Row="1">
                    <TextBlock Text="{Binding selected_scheme.path}" />
                </Grid>

当您单击某些ListBox时,如果您单击尚未选择的项目,则所选项目不会更改。

2 个答案:

答案 0 :(得分:2)

首先,您应该定义ItemsSource的{​​{1}}和TabItem ListBox。 然后,您可以将他们的ViewModel绑定到ViewModel中的属性。

这是一个代码示例(我太懒了,无法创建一个单独的ViewModel类,因此它与我的主窗口类混合在一起,但你明白了......):

Codebehind:

SelectedItem

xaml:

namespace WpfApplication13
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private object _currentlySelectedItem;

        public object CurrentlySelectedItem
        {
            get { return _currentlySelectedItem; }

            set
            {
                _currentlySelectedItem = value;

                if (this.PropertyChanged != null)
                {
                    this.PropertyChanged(this, new PropertyChangedEventArgs("CurrentlySelectedItem"));
                }
            }
        }

        public class MyClass
        {
            public string MyString { get; set; }

            public MyClass(string myString)
            {
                this.MyString = myString;
            }
        }

        private List<MyClass> _myItemsSource = new List<MyClass>
                                               { 
                                                  new MyClass("toto"),
                                                  new MyClass("tata") 
                                               };

        public List<MyClass> MyItemsSource
        {
            get { return _myItemsSource; }
            set { _myItemsSource = value; }
        }

        public object A
        {
            get { return "toto"; }
        }

        public object B
        {
            get { return "tata"; }
        }

        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = this;
        }
    }
}

答案 1 :(得分:1)

编辑后的新答案:

将同一对象绑定到包含不同元素的两个不同列表的SelectedItem属性没有多大意义。您必须重新设计您的应用程序,否则您可能会遇到许多问题,因为未来这种奇怪的设计。

尽管如此,您仍然希望通过一些代码优化来实现。当用户单击其中一个ListBox时,您将其他列表框的选定项设置为null。然后,当您重新单击第一个列表框时,您将收到通知,因为选择从null变为某些内容。

XAML:

<Window x:Class="WpfApplication13.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel>
            <ListBox x:Name="ListBoxViewPresenter"
                     SelectedItem="{Binding CurrentlySelectedItem}" 
                     ItemsSource="{Binding MyItemsSource}" />
            <ListBox x:Name="ListBoxViewPresenter2"
                     SelectedItem="{Binding CurrentlySelectedItem}" 
                     ItemsSource="{Binding MyItemsSource2}" />
        </StackPanel>
    </Grid>
</Window>

代码隐藏:

using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using System.ComponentModel;

namespace WpfApplication13
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        private object _currentlySelectedItem;

        public object CurrentlySelectedItem
        {
            get { return _currentlySelectedItem; }

            set
            {
                _currentlySelectedItem = value;

                if (this.PropertyChanged != null)
                {
                    this.PropertyChanged(this, new PropertyChangedEventArgs("CurrentlySelectedItem"));
                }
            }
        }

        private List<int> _myItemsSource = new List<int> { 1, 2 };

        private List<int> _myItemsSource2 = new List<int> { 3, 4 };

        public List<int> MyItemsSource
        {
            get { return _myItemsSource; }
            set { _myItemsSource = value; }
        }


        public List<int> MyItemsSource2
        {
            get { return _myItemsSource2; }
            set { _myItemsSource2 = value; }
        }

        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = this;

            ListBoxViewPresenter.PreviewMouseDown += ListBoxViewPresenter_PreviewMouseDown;
            ListBoxViewPresenter2.PreviewMouseDown += ListBoxViewPresenter2_PreviewMouseDown;
        }

        void ListBoxViewPresenter_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            ListBoxViewPresenter2.SelectedItem = null;
        }

        void ListBoxViewPresenter2_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            ListBoxViewPresenter.SelectedItem = null;
        }
    }
}