我已经实现了违反MVVM模式的东西,我想知道是否有MVVM方法可以做到这一点。
我有一个Window MainWindow
,它的DataContext绑定到一个名为ViewModel
的类,它实现了INotifyPropertyChanged
。
我还实现了一个窗口ChildWindow
,当使用RelayCommand
单击按钮时,该窗口以“对话框”样式显示。 ChildWindow
的DataContext也绑定到ViewModel
。此窗口用于填充新列表项的详细信息。我将视图作为CommandParameter
传递给ViewModel
,以便ChildWindow
与MainWindow
相比可以居中。这不是MVVM,我想改变它。
首先,我以非MVVM的方式实现了这个:
以下是MainWindow
中按钮的XAML打开ChildWindow
:
<Button Name="BtnInsert" Width="50" Margin="10" Command="{Binding OpenChildWindowCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}">Add</Button>
这是我对ChildWindow的简化XAML:
<Window x:Class="HWE_Einteilen_Prototype.View.ListItemWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HWE_Einteilen_Prototype.View"
mc:Ignorable="d"
Title="test" Height="400" Width="400">
<TextBox Width="50" Text="{Binding CurrentListItem.Id}" ></TextBox>
</Window>
这是我的(简化)ViewModel类:
public class ViewModel : INotifyPropertyChanged
{
private DataContext _ctx;
private ListItem _currentListItem;
private ObservableCollection<listItem> _listItems;
private ListItemWindow _listItemWindow;
private ICommand _openListItemWindowCommand;
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<ListItem> ListItems
{
get { return _listItems; }
set
{
_listItems = value;
OnPropertyChanged();
}
}
public ListItem CurrentListItem
{
get { return _currentListItem; }
set
{
_currentListItem = value;
OnPropertyChanged();
}
}
public ICommand OpenListItemWindowCommand
{
get { return _openListItemWindowCommand; }
set
{
_openListItemWindowCommand = value;
OnPropertyChanged();
}
}
public ViewModel()
{
OpenListItemWindowCommand = new RelayCommand(this.OpenNewListItemWindow, this.CanOpenListItemWindow);
}
private void OpenNewListItemWindow(object parameter)
{
CurrentListItem = new listItem(){Id = "testId"};
_listItemWindow = new StListItemWindow(){DataContext = this};
_listItemWindow.Owner = (MainWindow)parameter;
_listItemWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
_listItemWindow.Closing += OnStListItemWindowClosing;
_listItemWindow.Show();
}
private bool CanOpenListItemWindow(object parameter)
{
return true;
}
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
我尝试了什么:
我已经尝试为打开子窗口的按钮实现一个Behavior(来自system.windows.interactivity),这样它就会创建一个新窗口并完成所有居中和所有者的东西,并且只在命令方法中保留CurrentListItem = new listItem(){Id = "testId"};
。但是,在这种情况下,绑定到ChildWindow中的CurrentListItem会引发异常。
MainWindow
按钮的XAML代码:
<Button Name="BtnInsert" Width="50" Margin="10" Command="{Binding OpenListItemWindowCommand}" Content="Add">
<i:Interaction.Behaviors>
<behaviors:BehButtonNewWindow></behaviors:BehButtonNewWindow>
</i:Interaction.Behaviors>
</Button>
行为代码:
class BehButtonNewWindow : Behavior<Button>
{
private StListItemWindow _ListItemWindow;
protected override void OnAttached()
{
AssociatedObject.Click += OnClickHandler;
}
protected override void OnDetaching()
{
AssociatedObject.Click -= OnClickHandler;
}
private void OnClickHandler(object sender, RoutedEventArgs routedEventArgs)
{
if (sender is Button button)
{
var win = Window.GetWindow(button);
if (win != null)
{
_ListItemWindow = new ListItemWindow
{
DataContext = win.DataContext,
Owner = win,
WindowStartupLocation = WindowStartupLocation.CenterOwner
};
_ListItemWindow.Show();
}
}
}
}
ViewModel的命令执行方法:
private void OpenNewStListItemWindow(object parameter)
{
CurrentListItem = new ListItem(){Id = "testId"};
}
我做错了什么?
答案 0 :(得分:0)
这个答案归功于威尔(见评论)
处理窗口时:
打开一个窗口是一个UI问题。只需处理代码隐藏中的按钮单击,构建一个新窗口并将当前VM粘贴在其中。 MVVM!=没有代码隐藏。
关于处理vm代码:
[...]如果您的意思是底部的最后一点代码,请将其公开并让窗口在打开新窗口之前调用它。知道您的视图模型,UI非常精细。它们旨在显示其状态并绑定到其属性。
感谢您的帮助!