我有MainWindow和AddEdit UserControl.在里面MainWindow我渲染这个AddEdit <Views:AddEditData />,之前这个命名空间被添加到Window元素:
xmlns:Views="clr-namespace:MyProject.WPF.Views"
+++++++++++++++ ++++++++++++++++
ListOfData + + DataDetails +
+ + +
DataOne + + Name: txtBox1+
DataTwo + + +
DataThree + + +
+ + Save data +
+++++++++++++++ ++++++++++++++++
Run Code Online (Sandbox Code Playgroud)
当用户选择左侧的数据时(例如DataTwo)我想在AddEdit用户控件(DataDetails面板)中显示它的属性(为简单起见,只有Name属性).
由于这UserControl是与MainWindow分开存储的,我应该使用相同的MainWindowViewModel和相同的datacontext,还是应该为AddEdit创建单独的ViewModel UserControl?
希望这听起来很清楚,如果不是,请询问详细信息.
Part 1. Display the properties of the control in MVVM
正如我在评论中所说:
在MVVM中,ViewModel不应该知道所在的控件.在这种情况下,请使用附加的行为或在View中保留相同的侧逻辑
ViewModel与a没有直接关联View,所以只需参考控件的名称就不对了.最好在中设置一个属性Model,并将其绑定到Viewvia中ViewModel,但该属性Name不支持Binding(来自MSDN的引用):
数据绑定名称在技术上是可行的,但是这是一种非常罕见的情况,因为数据绑定名称无法满足属性的主要用途:为代码隐藏提供标识符连接点.
所以我建议使用该Tag属性或Uid.在我的例子中(给出一个下面的),我将Uid属性用于这些目的.
Part 2. Communication via ViewModels (pattern Mediator)
介体模式有几个实施例,但我最喜欢的实现XAML Guy,它简单明了 - 介体模式.
Implementation 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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
为了展示他的作品,我创建了一个小例子,它由两个组成Views,每个都有自己的ViewModel和Model.
项目结构如下所示:

Output

当您单击Button时,ListOfData ViewModel通过介体与DataDetails进行通信ViewModel,因此:
Mediator.NotifyColleagues("ShowDetails", true);
Mediator.NotifyColleagues("SetSelectedFruit", ListOfDataModel.FruitGreen);
Run Code Online (Sandbox Code Playgroud)
与属性交互的所有过程必须注册ViewModel如下:
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);
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中我用一个DataTemplate代替UserControl.以下是该项目的主要部分:
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>
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
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>
Run Code Online (Sandbox Code Playgroud)
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>
Run Code Online (Sandbox Code Playgroud)
该项目可在此链接中找到.
| 归档时间: |
|
| 查看次数: |
2582 次 |
| 最近记录: |