C# WPF MVVM:数据网格的显示视图';s SelectedItem
我是MVVM和WPF的新手,对这个问题已经完全挂断了一段时间。我试图在DataGrid中显示基于SelectedItem的视图(UserControl)。UserControl使用构造函数中的数据集呈现,但从不更新 我真的很感激在这方面有经验的人的一些见解。我尝试通过setUpdateCallback添加中介,现在datagrid中的第一行使用我单击的其他行的值进行更新,但这显然不是我想要的,我需要在datagrid之外的单独客户端视图中进行这些更新 ClientPanel.xamlC# WPF MVVM:数据网格的显示视图';s SelectedItem,c#,wpf,xaml,mvvm,datagrid,C#,Wpf,Xaml,Mvvm,Datagrid,我是MVVM和WPF的新手,对这个问题已经完全挂断了一段时间。我试图在DataGrid中显示基于SelectedItem的视图(UserControl)。UserControl使用构造函数中的数据集呈现,但从不更新 我真的很感激在这方面有经验的人的一些见解。我尝试通过setUpdateCallback添加中介,现在datagrid中的第一行使用我单击的其他行的值进行更新,但这显然不是我想要的,我需要在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>
<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>
非常基本的MVVM框架
可观察对象.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");
}
}
}
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
);
}
}
}
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 ) );
}
}
}
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
}
}
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
}
}
Mediator.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");
}
}
}
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
);
}
}
}
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 ) );
}
}
}
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
}
}
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
}
}
使用系统;
使用B2BNet.lib;
命名空间B2BNet.MVVM
{
///
///可用的交叉视图模型消息
///
公共枚举ViewModelMessages{UpdateClientViews=1,
DebugUpdated=2
};
公共密封类调解员
{
#区域数据
静态只读中介实例=new Mediator();
私有易失性对象锁定器=新对象();
多字典内部列表
=新的多字典();
#端区
#区域导体
//演员
静态介体()
{
}
私人调解人()
{
}
#端区
#区域公共财产
///
///单例实例
///
公共静态中介实例
{
得到
{
返回实例;
}
}
#端区
#区域公共方法
///
///注册对特定消息的回调
///
///要使用的回调函数
///当它看到消息时
///传达给
///注册到
公共无效寄存器(操作回调,
ViewModelMessages(消息)
{
AddValue(消息、回调);
}
///
///通知注册到特定消息的所有回调
///
///通知人的消息
///消息的参数
公共无效通知(ViewModelMessages消息,
对象参数)
{
if(internalList.ContainsKey(消息))
{
//将消息转发给所有侦听器
foreach(中的操作回调)
内部列表[消息])
回调(args);
}
}
#端区
}
}
DelegateCommand.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");
}
}
}
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
);
}
}
}
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 ) );
}
}
}
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
}
}
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
}
}
使用系统;
使用System.Windows.Input;
命名空间B2BNet.MVVM
{
公共类DelegateCommand:ICommand
{
私有只读操作\u操作;
公共委托人命令(操作)
{
_行动=行动;
}
public void Execute(对象参数)
{
_作用(参数);
}
公共布尔CanExecute(对象参数)
{
返回true;
}
#pragma警告禁用67
公共事件处理程序CanExecuteChanged;
#pragma警告恢复67
}
}
解决方案
解决办法很简单。谢谢你的快速回复,瑞秋:)。我简单地从每个视图中删除了以下内容:
<!--<Grid.DataContext>
<VM:ClientPanel/>
</Grid.DataContext>-->
<!--<Grid.DataContext>
<VM:Client/>
</Grid.DataContext>-->
它工作得非常完美,甚至允许我更新datagrid:
哦,天哪,这是一大堆代码,我不确定我是否理解你想做的每件事。以下是使用WPF绑定时的几个重要注意事项
问题是您正在用户控件中硬编码DataContext
因此,您的
客户端
用户控件将其DataContext硬编码为客户端
的新实例,并且它与您的客户端面板
用户控件使用的实例不同。因此,您的视图模型是私有的,我刚刚将类更新为public,但行为是相同的。我注意到的第一件事是,您的用户控制硬编码DataContext,这意味着不能向其中传递DataContext。这可能是你的问题。这解决了我的问题!非常感谢你!我确信我需要DataContext,因为我有它,所以我一直在错误的地方寻找答案。但我现在对它的工作原理有点困惑,因为我刚刚意识到,如果我所做的唯一更改是注释掉硬编码的DataContext,那么我就不需要添加DataContext=“{…}”在ClientPanel或在客户端…我相信你的其他帖子也回答了这个问题。我有一个此ClientPanel所在的父MainWindowView。在这一点上,我定义:@CorbinTarrant很高兴你把它解决了!DataContext是我经常看到WPF初学者对它感到困惑的东西,实际上我写了一篇关于它的博客文章,只是为了链接,如果你感兴趣的话——它可能比我在评论中能更好地解释事情:)