简体   繁体   English

将ItemsControl中的viewmodel绑定到自定义用户控件

[英]Binding viewmodel within ItemsControl to custom user control

I'm modernising an application (from Windows Forms and VB.Net to WPF) that displays a list of recent messages to a user. 我正在现代化一个应用程序(从Windows窗体和VB.Net到WPF),该应用程序向用户显示最近的消息列表。 I've created a MessageViewModel , a MessagesListViewModel and two custom user controls MessageListUserControl and MessageUserControl . 我创建了一个MessageViewModel ,一个MessagesListViewModel和两个自定义用户控件MessageListUserControlMessageUserControl

Messages are listed using an ItemsControl in the MessageListUserControl in a vertical stack panel and are rendered using a MessageuserControl . 使用垂直堆栈面板的MessageListUserControl中的ItemsControl列出消息,并使用MessageuserControl呈现MessageuserControl However, all of the messages have the Message property set to null , rather than the current message. 但是,所有消息的Message属性都设置为null ,而不是当前消息。

I've included below my code, if anybody has any ideas about how to fix the bindings, I'd be extremely grateful as this is my first go with WPF. 我已经在我的代码下面包含了代码,如果有人对如何解决绑定有任何想法,我将不胜感激,因为这是我第一次使用WPF。

MessageViewModel MessageViewModel

using System;
using System.ComponentModel;

namespace TestApp
{
    public class MessageViewModel : INotifyPropertyChanged
    {
        private string _sender;

        private string _subject;

        private string _content;

        public event PropertyChangedEventHandler PropertyChanged;

        public string Sender
        {
            get { return _sender; }
            set
            {
                _sender = value;
                NotifyPropertyChanged("Sender");
            }
        }

        public string Subject
        {
            get { return _subject; }
            set
            {
                _subject = value;
                NotifyPropertyChanged("Subject");
            }
        }

        public string Content
        {
            get { return _content; }
            set
            {
                _content = value.Trim();
                NotifyPropertyChanged("Content");
            }
        }

        private void NotifyPropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }
    }
}

MessageListViewModel MessageListViewModel

using System.Collections.ObjectModel;

namespace TestApp
{
    public class MessageListViewModel
    {
        private readonly ObservableCollection<MessageViewModel> _messages;

        public ObservableCollection<MessageViewModel> Messages
        {
            get { return _messages; }
        }

        public MessageListViewModel()
        {
            _messages = new ObservableCollection<MessageViewModel>();
        }

        #region Methods
        public void AddMessage(string sender, string subject, string content)
        {

            var vm = new MessageViewModel()
            {
                Sender = sender,
                Subject = subject,
                Content = content,
            };
            _messages.Insert(0, vm); // Insert it at the top of the list.
        }
        #endregion // Methods
    }
}

MessageUserControl MessageUserControl

<UserControl x:Class="TestApp.MessageUserControl"
             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:TestApp"
             mc:Ignorable="d" x:Name="MessageCtrl" Background="White"
             d:DesignHeight="300" d:DesignWidth="300">
    <DockPanel>
        <Border BorderThickness="0,0,0,1" BorderBrush="DarkGray" DockPanel.Dock="Top">
            <Grid DockPanel.Dock="Top">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="60"/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>

                <Grid.RowDefinitions>
                    <RowDefinition/>
                    <RowDefinition/>
                </Grid.RowDefinitions>

                <TextBlock Name="lblSender" Text="Sender" HorizontalAlignment="Left" Grid.Row="0" Grid.Column="0" FontWeight="Bold" Padding="5"/>
                <TextBlock Name="txtSender" Text="{Binding Path=Sender, Mode=TwoWay}" HorizontalAlignment="Stretch" Grid.Row="0" Grid.Column="1" Padding="5"/>

                <TextBlock Name="lblSubject" Text="Subject" HorizontalAlignment="Left" Grid.Row="1" Grid.Column="0" FontWeight="Bold" Padding="5"/>
                <TextBlock Name="txtSubject" Text="{Binding Path=Subject, Mode=TwoWay}" HorizontalAlignment="Stretch" Grid.Row="1" Grid.Column="1" Padding="5"/>
            </Grid>
        </Border>

        <TextBox BorderThickness="0" Background="Transparent" IsReadOnly="True" Name="txtMessageContent" Text="{Binding Path=Content, Mode=TwoWay}" DockPanel.Dock="Top" Padding="5" VerticalAlignment="Center" HorizontalAlignment="Stretch" TextWrapping="WrapWithOverflow" />
    </DockPanel>
</UserControl>

MessageListUserControl MessageListUserControl

<UserControl x:Class="TestApp.MessageListUserControl"
             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:TestApp"
             mc:Ignorable="d" Background="White" x:Name="MessagesListCtrl"
             d:DesignHeight="300" d:DesignWidth="300">
    <DockPanel>
        <ItemsControl x:Name="MessagesStack" Grid.Column="0" ItemsSource="{Binding Path=Messages}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Vertical"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <local:MessageControl Message="{Binding Path=., Mode=TwoWay}" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </DockPanel>
</UserControl>

The result ends up looking like the following, with an empty subject, sender and content: 结果最终如下所示,主题,发件人和内容为空:

空消息详细信息

I've also tried setting the binding in the DataTemplate in MessageListUserControl to {Binding /} as found here with no success, as well as setting DataContext={Binding} . 我也试着设置在绑定DataTemplateMessageListUserControl{Binding /}如发现这里没有成功,以及设置DataContext={Binding}

When I move the template XAML for the single message display directly into the DataTemplate , everything works fine but I wish to separate it into a separate control to perform some extra logic on it. 当我将用于单个消息显示的模板XAML直接移动到DataTemplate ,一切正常,但是我希望将其分离到一个单独的控件中,以对它执行一些额外的逻辑。

Remove Message property from 从中删除Message属性

<local:MessageControl Message="{Binding Path=., Mode=TwoWay}" />

It is not needed at all. 完全不需要。

Remove DataContext from MessageControl which you have already done now. MessageControl中删除DataContext ,您现在已经完成了它。

Everything remaining same, now it will work. 一切保持不变,现在可以正常工作。

The DataTemplate will get it's DataContext automatically as MessageViewModel . DataTemplate将自动以MessageViewModel获取其DataContext

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM