繁体   English   中英

WPF MVVM:DataGrid的SelectedItem的显示视图

[英]WPF MVVM: Display View for DataGrid's SelectedItem

我是MVVM和WPF的新手,并且已经完全挂了一段时间了。 我正在尝试基于DataGrid中的SelectedItem显示视图(UserControl)。 UserControl使用构造函数中的数据集进行渲染,但永远不会更新。

在此处输入图片说明

我真的很感谢有经验的人的一些见解。 我尝试通过setUpdateCallback添加一个Mediator,现在datagrid的第一行更新了我单击的其他行的值,但这显然不是我想要的,我需要这些更新在外部的单独客户端视图中进行数据网格。

ClientPanel.xaml

<UserControl x:Class="B2BNet.View.ClientPanel" 
         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:VM="clr-namespace:B2BNet.ViewModel"
         xmlns:V="clr-namespace:B2BNet.View"
         xmlns:local="clr-namespace:B2BNet"
         xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
         mc:Ignorable="d">
<Grid>
    <Grid.DataContext>
        <VM:ClientPanel/>
    </Grid.DataContext>
    <TextBlock HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="43" Width="280" Text="{Binding Title}" FontSize="36" FontFamily="Global Monospace"/>
    <DataGrid AutoGenerateColumns="False" x:Name="dataGrid" HorizontalAlignment="Left" Margin="10,60,0,10" VerticalAlignment="Top" ItemsSource="{Binding Clients}" SelectedItem="{Binding currentClient}">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name" Binding="{Binding name}"></DataGridTextColumn>
            <DataGridTextColumn Header="Active" Binding="{Binding active}"></DataGridTextColumn>
            <DataGridTextColumn Header="Status" Binding="{Binding status}"></DataGridTextColumn>
        </DataGrid.Columns>
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="SelectionChanged">
                <i:InvokeCommandAction Command="{Binding clientSelectionChanged_command}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </DataGrid>
    <V:Client HorizontalAlignment="Left" Margin="163,58,-140,0" VerticalAlignment="Top" Content="{Binding currentClient}" Height="97" Width="201"/>
</Grid>

Client.xaml

<UserControl x:Class="B2BNet.View.Client"
         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:VM="clr-namespace:B2BNet.ViewModel"
         xmlns:local="clr-namespace:B2BNet"
         mc:Ignorable="d">
<Grid>
    <Grid.DataContext>
        <VM:Client/>
    </Grid.DataContext>
    <Label x:Name="name" Content="Name:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
    <Label x:Name="active" Content="Active:" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="9,41,0,0"/>
    <Label x:Name="status" Content="Status:" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,72,0,0"/>
    <Label x:Name="namevalue" HorizontalAlignment="Left" Margin="59,10,0,0" VerticalAlignment="Top" Width="200" Height="26" Content="{Binding name}"/>
    <Label x:Name="activevalue" HorizontalAlignment="Left" Margin="59,41,0,0" VerticalAlignment="Top" Width="200" Height="26" Content="{Binding active}"/>
    <Label x:Name="statusvalue" HorizontalAlignment="Left" Margin="60,67,-1,0" VerticalAlignment="Top" Width="200" Height="26" Content="{Binding status}"/>

</Grid>

ViewModel-ClientPanel.cs

using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using B2BNet.MVVM;

namespace B2BNet.ViewModel
{
    public class ClientPanel : ObservableObject
    {
        public string Title { get; set; }

        private Client _currentClient;
        public Client currentClient
        {
            get
            {
                return _currentClient;
            }
            set
            {
                _currentClient = value;
                RaisePropertyChangedEvent( "currentClient" );
                Utility.print("currentClient Changed: " + _currentClient.name);
                Mediator.Instance.Notify(ViewModelMessages.UpdateClientViews, currentClient);
            }
        }

        private ObservableCollection<Client> _Clients;
        public ObservableCollection<Client> Clients
        {
            get
            {
                return _Clients;
            }
            set
            {
                _Clients = value;
                RaisePropertyChangedEvent("Clients");
                Utility.print("Clients Changed");
            }
        }


        public ClientPanel()
        {
            Title = "Clients";
            Clients = new ObservableCollection<Client>();

            for ( int i = 0; i < 10; i++ )
            {
                Clients.Add( new Client { name = "Client-" + i, status = "Current", active = true } );
            }
            currentClient = Clients.First();
            currentClient.setUpdateCallback();
        }

        ////////////
        //COMMANDS//
        ////////////
        public ICommand clientSelectionChanged_command
        {
            get { return new DelegateCommand( clientSelectionChanged ); }
        }
        private void clientSelectionChanged( object parameter )
        {
            B2BNet.Utility.print("clientSelectionChanged");
        }
    }
}

ViewModel-Client.cs

using System;
using B2BNet.MVVM;

namespace B2BNet.ViewModel
{
    public class Client : ObservableObject
    {

        private String _name;
        public String name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
                RaisePropertyChangedEvent( "name" );
                Utility.print("Client.name changed: " + value );
            }
        }

        private Boolean _active;
        public Boolean active
        {
            get
            {
                return _active;
            }
            set
            {
                _active = value;
                RaisePropertyChangedEvent( "active" );
                Utility.print("Client.active changed" + value );
            }
        }

        private String _status;
        public String status
        {
            get
            {
                return _status;
            }
            set
            {
                _status = value;
                RaisePropertyChangedEvent( "status" );
                Utility.print("Client.status changed" + value );
            }
        }

        public Client()
        {
            name = "Set in Client Constuctor";
            status = "Set in Client Constructor";
        }

        public void setUpdateCallback()
        {
            ////////////
            //Mediator//
            ////////////
            //Register a callback with the Mediator for Client
            Mediator.Instance.Register(
                (Object o) =>
                {
                    Client client = (Client)o;
                    name = client.name;
                    active = client.active;
                    status = client.status;
                }, B2BNet.MVVM.ViewModelMessages.UpdateClientViews
            );
        }
   }
}

非常基本的MVVM框架

ObservableObject.cs

using System.ComponentModel;

namespace B2BNet.MVVM
{
    public class ObservableObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChangedEvent( string propertyName )
        {
            var handler = PropertyChanged;
            if ( handler != null )
                handler( this, new PropertyChangedEventArgs( propertyName ) );
        }
    }
}

Mediator.cs

using System;
using B2BNet.lib;

namespace B2BNet.MVVM
{
    /// <summary>
    /// Available cross ViewModel messages
    /// </summary>
    public enum ViewModelMessages { UpdateClientViews = 1,
                                    DebugUpdated = 2
                                   };


    public sealed class Mediator
    {
        #region Data
        static readonly Mediator instance = new Mediator();
        private volatile object locker = new object();

        MultiDictionary<ViewModelMessages, Action<Object>> internalList
            = new MultiDictionary<ViewModelMessages, Action<Object>>();
        #endregion

        #region Ctor
        //CTORs
        static Mediator()
        {


        }

        private Mediator()
        {

        }
        #endregion

        #region Public Properties

        /// <summary>
        /// The singleton instance
        /// </summary>
        public static Mediator Instance
        {
            get
            {
                return instance;
            }
        }

        #endregion

        #region Public Methods
        /// <summary>
        /// Registers a callback to a specific message
        /// </summary>
        /// <param name="callback">The callback to use 
        /// when the message it seen</param>
        /// <param name="message">The message to 
        /// register to</param>
        public void Register(Action<Object> callback, 
            ViewModelMessages message)
        {
            internalList.AddValue(message, callback);
        }


        /// <summary>
        /// Notify all callbacks that are registed to the specific message
        /// </summary>
        /// <param name="message">The message for the notify by</param>
        /// <param name="args">The arguments for the message</param>
        public void Notify(ViewModelMessages message, 
            object args)
        {
            if (internalList.ContainsKey(message))
            {
                //forward the message to all listeners
                foreach (Action<object> callback in 
                    internalList[message])
                        callback(args);
            }
        }
        #endregion    
    }
}

DelegateCommand.cs

using System;
using System.Windows.Input;

namespace B2BNet.MVVM
{
    public class DelegateCommand : ICommand
    {
        private readonly Action<object> _action;

        public DelegateCommand( Action<object> action )
        {
            _action = action;
        }

        public void Execute( object parameter )
        {
            _action( parameter );
        }

        public bool CanExecute( object parameter )
        {
            return true;
        }

        #pragma warning disable 67
        public event EventHandler CanExecuteChanged;
        #pragma warning restore 67
    }
}

解决方案

解决方案很简单。 感谢Rachel的快速回复:)。 我简单地从每个视图中删除了以下内容:

<!--<Grid.DataContext>
        <VM:ClientPanel/>
    </Grid.DataContext>-->

<!--<Grid.DataContext>
        <VM:Client/>
    </Grid.DataContext>-->

并且它运行完美,甚至允许我更新数据网格:

在此处输入图片说明

问题是您要在UserControls中对DataContext进行硬编码。

因此,您的Client UserControl已将其DataContext硬编码为Client的新实例,并且与ClientPanel UserControl使用的实例不同。 因此, <V:Client Content="{Binding currentClient}"绑定指向的属性实例不同于DataGrid使用的实例。

所以摆脱

<Grid.DataContext>
    <VM:Client/>
</Grid.DataContext>

并将您的Content绑定更改为DataContext

<V:Client DataContext="{Binding currentClient}" .../>

它应该可以正常工作。

我以为我肯定对为什么不应该对UserControl的DataContext属性进行硬编码感到有些恼火,但是我现在能找到的最接近的东西是this 希望它可以帮助您:)

哦,男孩,这是很多代码,我不确定我是否了解您要尝试执行的所有操作。 与WPF绑定时,有一些重要说明。

  1. 确保属性具有公共属性{get; 组; }
  2. 如果该值将要更改,请确保将Mode = TwoWay,UpdateSourceTrigger = PropertyChanged添加到绑定中。 这样可以使您的视图和视图模型保持同步,并告诉彼此进行更新。
  3. 将ObservableCollections和BindingLists用于集合。 列表似乎效果不佳。
  4. 确保DataContext与您要绑定到的属性匹配。 如果您的DataContext没有这些属性,则它们将不会更新。

暂无
暂无

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

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