如何使用MVVM管理列表框中的用户控件?

时间:2016-06-10 20:48:12

标签: c# wpf mvvm

我知道有很多这方面的问题,但我找不到正确的答案,或者我不明白正确的解决方法。 我在MainWindows中有我的列表框,它由自定义对象(FooObjClass)填充。

<ListBox x:Name="FooListBox">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <fooNameSpace:FooObjView/>                    
            </DataTemplate>
        </ListBox.ItemTemplate>
</ListBox>

FooObjView是一个用户控件

<UserControl x:Class="PLCS7_TEST.SmartObjRecognize.SmartObjView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:Test.FooObjRecognize"
         mc:Ignorable="d" Width="Auto">
<UserControl.DataContext>
    <local:FooViewModel/>
</UserControl.DataContext>
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <TextBlock Grid.Column="0" Text="{Binding Path=FooObjprop.Name}"/> 
    <TextBlock Grid.Column="1" Text="{Binding Path=FooObjprop.Type}">
</Grid>

这是我的FooViewModel

 class FooViewModel : ObservableObject
{
    private FooObjClass fooObjmember;

    public FooObjClass FooObjprop
    {
        get { return fooObjmember; }
        set
        {
            this.fooObjmember= value;
            base.RaisePropertyChanged("FooObjprop");
        }
    }
}

FooObjClass是一个普通类,ObservableObject类是这样的:

public abstract class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, e);
        }
    }

    protected void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpresssion)
    {
        var propertyName = PropertySupport.ExtractPropertyName(propertyExpresssion);
        this.RaisePropertyChanged(propertyName);
    }

    protected void RaisePropertyChanged(String propertyName)
    {
        VerifyPropertyName(propertyName);
        OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
    }

    public void VerifyPropertyName(String propertyName)
    {
        // verify that the property name matches a real,  
        // public, instance property on this Object.
        if (TypeDescriptor.GetProperties(this)[propertyName] == null)
        {
            Debug.Fail("Invalid property name: " + propertyName);
        }
    }
}

现在,我能做些什么来将列表框的项目对象(它是一个FooObjClass)传递给最后一个FooModelView?我必须使用依赖属性?但是怎么样?我尝试了所有,但我没有找到解决方案

使用这段代码我会将列表框的item对象传递给FooViewModel

<UserControl.DataContext>
    <local:FooViewModel fooObjmember="{Databinding}"/>
</UserControl.DataContext>

但是fooObjmember不是依赖属性,当我尝试创建依赖属性时它是相同的

谢谢你,对不起我的英语;)

1 个答案:

答案 0 :(得分:0)

欢迎,

以下是您的错误:

  • 您没有指定ListBoxItem的绑定
  • 您正在UserControl中实例化另一个模型
  • 您绑定到字段fooObjmember,只允许属性

这是一个有效的例子:

Window XAML

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <!--<ListBox ItemsSource="{Binding}"> binds to DataContext property-->
        <ListBox ItemsSource="{Binding}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <local:MyUserControl DataContext="{Binding}" />
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

窗口代码

using System.Collections.Generic;

namespace WpfApplication1
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();

            DataContext = new List<MyModel>
            {
                new MyModel {Number = 1, Value = "one"},
                new MyModel {Number = 2, Value = "two"}
            };
        }
    }
}

用户控制XAML

<UserControl x:Class="WpfApplication1.MyUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:WpfApplication1"
             mc:Ignorable="d" d:DataContext="{d:DesignInstance local:MyModel}"
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Border Padding="5" BorderBrush="Red" BorderThickness="1">
            <StackPanel>
                <TextBlock Text="{Binding Number}" />
                <TextBlock Text="{Binding Value}" />
            </StackPanel>
        </Border>
    </Grid>
</UserControl>

用户控制代码

namespace WpfApplication1
{
    public partial class MyUserControl
    {
        public MyUserControl()
        {
            InitializeComponent();
        }
    }
}

型号代码

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WpfApplication1
{
    internal class MyModel : INotifyPropertyChanged
    {
        private int _number;
        private string _value;

        public int Number
        {
            get { return _number; }
            set
            {
                if (value == _number) return;
                _number = value;
                OnPropertyChanged();
            }
        }

        public string Value
        {
            get { return _value; }
            set
            {
                if (value == _value) return;
                _value = value;
                OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

<强>结果

enter image description here

现在根据您的需要调整:D