我有主窗口
和 AddEdit
用户控件
。在主窗口
我使这个AddEdit像<浏览次数:AddEditData />
,previous此命名空间添加到窗口元素:
I have MainWindow
and AddEdit
UserControl
. Inside MainWindow
I render this AddEdit like <Views:AddEditData />
, previous this namespace is added to Window element:
xmlns:Views="clr-namespace:MyProject.WPF.Views"
+++++++++++++++ ++++++++++++++++
ListOfData + + DataDetails +
+ + +
DataOne + + Name: txtBox1+
DataTwo + + +
DataThree + + +
+ + Save data +
+++++++++++++++ ++++++++++++++++
当用户选择的数据在左边(DataTwo为例)我想要显示它的属性(为简单起见仅Name属性)内AddEdit用户控件(DataDetails面板)。
When user selects data on left side (DataTwo for example) I want to display it's properties (for simplicity only Name property) inside AddEdit user control (DataDetails panel).
由于该用户控件
从主窗口分开存储的,我应该用同样的MainWindowViewModel和相同的DataContext还是应该创建分离视图模型为AddEdit 用户控件
?
Since this UserControl
is stored separately from the MainWindow should I use same MainWindowViewModel and same datacontext or should I create separated ViewModel for AddEdit UserControl
?
希望这听起来很清楚,如果不是请询问详情。
Hopefully this sounds clear, if not please ask for details.
第1部分显示在MVVM控件的属性
Part 1. Display the properties of the control in MVVM
正如我在评论说:
在MVVM视图模型不应该知道的控件,它的位置。在这种情况下,使用附加的行为或离开同方逻辑视图
In MVVM ViewModel should not know about the controls, which are located. In such cases, use the attached behavior or leave the same side logic in View
视图模型
不直接与相关的查看
,所以只是指控件的名称不会对。这将是最好的型号
设置一个属性,并通过将其绑定到
,但属性查看
视图模型名称
不支持绑定(引自 MSDN ):
ViewModel
is not directly associated with a View
, so just refer to the name of the control would not be right. It would be better to set a property in the Model
, and bind it into View
via ViewModel
, but the property Name
does not support Binding (quote from the MSDN):
数据绑定一个名字在技术上是可行的,但是是一个非常罕见的情况下,因为数据绑定名称不能成为财产的主要预期目标:提供code-后面的标识符的连接点。
Data binding a Name is technically possible, but is an extremely uncommon scenario because a data-bound Name cannot serve the main intended purpose of the property: to provide an identifier connection point for code-behind.
所以我建议使用标签
属性或的Uid
。在我的例子(给出如下图),我用的Uid
属性为这些目的。
so I suggest to use the Tag
property or Uid
. In my example (give an below), I use Uid
property for these purposes.
通过的ViewModels第2部分通信(模式中保)
Part 2. Communication via ViewModels (pattern Mediator)
有的中保的格局几个实施例,但我最喜欢的实施 XAML盖伊
这是简单而明确 - 的调解模式。
There are several embodiments of the Mediator pattern, but I like the most the implementation by XAML Guy
, it is simple and clear - The Mediator Pattern.
实施code
public static class Mediator
{
static IDictionary<string, List<Action<object>>> pl_dict = new Dictionary<string, List<Action<object>>>();
static public void Register(string token, Action<object> callback)
{
if (!pl_dict.ContainsKey(token))
{
var list = new List<Action<object>>();
list.Add(callback);
pl_dict.Add(token, list);
}
else
{
bool found = false;
foreach (var item in pl_dict[token])
if (item.Method.ToString() == callback.Method.ToString())
found = true;
if (!found)
pl_dict[token].Add(callback);
}
}
static public void Unregister(string token, Action<object> callback)
{
if (pl_dict.ContainsKey(token))
{
pl_dict[token].Remove(callback);
}
}
static public void NotifyColleagues(string token, object args)
{
if (pl_dict.ContainsKey(token))
{
foreach (var callback in pl_dict[token])
callback(args);
}
}
}
为了证明他的工作,我创建了一个小例子,它由两个浏览
,每个人都有自己的视图模型
和型号
。
To demonstrate his work, I created a small example, which consists of two Views
, each has its own ViewModel
and Model
.
该项目结构如下所示:
输出
当你点击按钮,ListOfData 视图模型
通过中介与DataDetails 视图模型
,从而通信
When you click on Button, ListOfData ViewModel
communicates via mediator with DataDetails ViewModel
, thus:
Mediator.NotifyColleagues("ShowDetails", true);
Mediator.NotifyColleagues("SetSelectedFruit", ListOfDataModel.FruitGreen);
这与性互动必须注册的所有程序的视图模型
是这样的:
All procedures that interact with the properties must register their ViewModel
like this:
private void ShowDetails_Mediator(object args)
{
bool showDetails = (bool)args;
if (showDetails == true)
{
DataDetailsModel.IsVisible = true;
}
else
{
DataDetailsModel.IsVisible = false;
}
}
private void SetSelectedFruit_Mediator(object args)
{
string selectedFruit = (string)args;
DataDetailsModel.SelectedFruit = selectedFruit;
}
public DataDetailsViewModel()
{
DataDetailsModel = new DataDetailsModel();
Mediator.Register("ShowDetails", ShowDetails_Mediator);
Mediator.Register("SetSelectedFruit", SetSelectedFruit_Mediator);
}
在这个例子中我使用了的DataTemplate
,而不是用户控件
。下面是该项目的主要部分:
In the example I used a DataTemplate
instead UserControl
. Below are the main part of the project:
MainWindow.xaml
<Window x:Class="CommunicateWithVM.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModels="clr-namespace:CommunicateWithVM.ViewModels"
Title="MainWindow"
WindowStartupLocation="CenterScreen"
Height="350"
Width="525">
<Grid>
<ContentControl Name="ListOfData"
ContentTemplate="{StaticResource ListOfDataView}">
<ViewModels:ListOfDataViewModel />
</ContentControl>
<ContentControl Name="DataDetails"
ContentTemplate="{StaticResource DataDetailsView}">
<ViewModels:DataDetailsViewModel />
</ContentControl>
</Grid>
</Window>
模式
Models
DataDetailsModel
public class DataDetailsModel : NotificationObject
{
#region SelectedFruit
private string _selectedFruit = "";
public string SelectedFruit
{
get
{
return _selectedFruit;
}
set
{
_selectedFruit = value;
NotifyPropertyChanged("SelectedFruit");
}
}
#endregion
#region IsVisible
private bool _isVisible = false;
public bool IsVisible
{
get
{
return _isVisible;
}
set
{
_isVisible = value;
NotifyPropertyChanged("IsVisible");
}
}
#endregion
}
ListOfDataModel
public class ListOfDataModel : NotificationObject
{
#region FruitGreen
private string _fruitGreen = "Apple";
public string FruitGreen
{
get
{
return _fruitGreen;
}
set
{
_fruitGreen = value;
NotifyPropertyChanged("FruitGreen");
}
}
#endregion
#region FruitYellow
private string _fruitYellow = "Limon";
public string FruitYellow
{
get
{
return _fruitYellow;
}
set
{
_fruitYellow = value;
NotifyPropertyChanged("FruitYellow");
}
}
#endregion
}
的ViewModels
ViewModels
DataDetailsViewModel
public class DataDetailsViewModel
{
#region DataDetailsModel
private DataDetailsModel _dataDetailsModel = null;
public DataDetailsModel DataDetailsModel
{
get
{
return _dataDetailsModel;
}
set
{
_dataDetailsModel = value;
}
}
#endregion
#region ShowDetails_Mediator
private void ShowDetails_Mediator(object args)
{
bool showDetails = (bool)args;
if (showDetails == true)
{
DataDetailsModel.IsVisible = true;
}
else
{
DataDetailsModel.IsVisible = false;
}
}
#endregion
#region SetSelectedFruit_Mediator
private void SetSelectedFruit_Mediator(object args)
{
string selectedFruit = (string)args;
DataDetailsModel.SelectedFruit = selectedFruit;
}
#endregion
#region DataDetailsViewModel Constructor
public DataDetailsViewModel()
{
DataDetailsModel = new DataDetailsModel();
Mediator.Register("ShowDetails", ShowDetails_Mediator);
Mediator.Register("SetSelectedFruit", SetSelectedFruit_Mediator);
}
#endregion
}
ListOfDataViewModel
public class ListOfDataViewModel
{
#region ListOfDataModel
private ListOfDataModel _listOfDataModel = null;
public ListOfDataModel ListOfDataModel
{
get
{
return _listOfDataModel;
}
set
{
_listOfDataModel = value;
}
}
#endregion
#region GreenButtonCommand
private ICommand _greenButtonCommand = null;
public ICommand GreenButtonCommand
{
get
{
if (_greenButtonCommand == null)
{
_greenButtonCommand = new RelayCommand(param => this.GreenButton(), null);
}
return _greenButtonCommand;
}
}
private void GreenButton()
{
Mediator.NotifyColleagues("ShowDetails", true);
Mediator.NotifyColleagues("SetSelectedFruit", ListOfDataModel.FruitGreen);
}
#endregion
#region YellowButtonCommand
private ICommand _yellowButtonCommand = null;
public ICommand YellowButtonCommand
{
get
{
if (_yellowButtonCommand == null)
{
_yellowButtonCommand = new RelayCommand(param => this.YellowButton(), null);
}
return _yellowButtonCommand;
}
}
private void YellowButton()
{
Mediator.NotifyColleagues("ShowDetails", true);
Mediator.NotifyColleagues("SetSelectedFruit", ListOfDataModel.FruitYellow);
}
#endregion
#region ListOfDataViewModel Constructor
public ListOfDataViewModel()
{
ListOfDataModel = new ListOfDataModel();
}
#endregion
}
浏览
Views
DataDetailsView
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModels="clr-namespace:CommunicateWithVM.ViewModels">
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<DataTemplate x:Key="DataDetailsView" DataType="{x:Type ViewModels:DataDetailsViewModel}">
<StackPanel Width="200"
Background="AliceBlue"
HorizontalAlignment="Right"
Visibility="{Binding Path=DataDetailsModel.IsVisible,
Converter={StaticResource BooleanToVisibilityConverter}}">
<TextBlock Text="Fruit: " />
<TextBlock Text="{Binding Path=DataDetailsModel.SelectedFruit}" />
</StackPanel>
</DataTemplate>
</ResourceDictionary>
ListOfDataView
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModels="clr-namespace:CommunicateWithVM.ViewModels">
<DataTemplate x:Key="ListOfDataView" DataType="{x:Type ViewModels:ListOfDataViewModel}">
<StackPanel Width="200"
Background="Azure"
HorizontalAlignment="Left">
<Button Uid="{Binding Path=ListOfDataModel.FruitGreen}"
Content="GreenButton"
Command="{Binding Path=GreenButtonCommand}" />
<Button Uid="{Binding Path=ListOfDataModel.FruitYellow}"
Content="YellowButton"
Command="{Binding Path=YellowButtonCommand}" />
</StackPanel>
</DataTemplate>
</ResourceDictionary>
此项目可在此链接。