所以我有一个包含两个 subview 的 View 。其中一个 subview 是带有文本框的屏幕键盘。下面是一些按钮,它们是不同 subview 的一部分。见下文:
当我按下键盘按钮时,它会在文本框中键入内容。带有按钮的 subview 和带有键盘的 subview 都有自己的 ViewModel。我的问题是,如何从按钮 View 中引用键盘 View (例如,这样我就可以获取文本字段的内容,或者如果用户单击“返回”则清除它)。
我正在尝试将其概念化,但我无法弄清楚如何获得与主视图相同的键盘 ViewModel 实例。
我可以创建一个变量:
private KeyboardViewModel keyboard;
但是我如何使用主视图已有的实例实例化该变量(以便我可以从按钮 View 模型访问这些属性)?
最佳答案
主要问题是,当实际上需要在多个 View/ViewModel 中重用数据源时,您将数据源错放在其中一个 ViewModel 中。您需要做的是将数据源重构为单例实例或可以注入(inject)不同 ViewModels 构造函数的单独实例。通过将数据源与特定的 ViewModel 解耦,可以让它在不同的地方自由访问。
public class DataCache
{
private static DataCache singletonInstance;
// You can have freedom to choose the event-driven model here
// Using traditional Event, EventAggregator, ReactiveX, etc
public EventHandler OnMessageChanged;
private DataCache()
{
}
public static DataCache Instance
{
get { return singletonInstance ?? (singletonInstance = new DataCache()); }
}
public string OnScreenMessage { get; set; }
public void AddStringToMessage(string c)
{
if (string.IsNullOrWhiteSpace(c)) return;
OnScreenMessage += c;
RaiseOnMessageChanged();
}
public void ClearMessage()
{
OnScreenMessage = string.Empty;
RaiseOnMessageChanged();
}
private void RaiseOnMessageChanged()
{
if (OnMessageChanged != null)
OnMessageChanged(null, null);
}
}
public class MainViewModel : ViewModelBase
{
private readonly MessageViewModel messageVM;
private readonly KeyboardViewModel keyboardVM;
private readonly ButtonsViewModel buttonsVM;
private readonly DataCache dataCache;
public MainViewModel()
{
messageVM = new MessageViewModel();
keyboardVM = new KeyboardViewModel();
buttonsVM = new ButtonsViewModel();
}
public ViewModelBase MessageViewModel { get { return messageVM; } }
public ViewModelBase KeyboardViewModel { get { return keyboardVM; } }
public ViewModelBase ButtonsViewModel { get { return buttonsVM; } }
}
public class MessageViewModel : ViewModelBase
{
private readonly DataCache dataCache = DataCache.Instance;
public MessageViewModel()
{
dataCache.OnMessageChanged += RaiseMessageChanged;
}
private void RaiseMessageChanged(object sender, EventArgs e)
{
OnPropertyChanged("Message");
}
public string Message
{
get { return dataCache.OnScreenMessage; }
set { dataCache.OnScreenMessage = value; }
}
}
public class KeyboardViewModel : ViewModelBase
{
private readonly DataCache dataCache = DataCache.Instance;
private ICommand onClickButtonCommand;
public ICommand OnClickButton
{
get
{
return onClickButtonCommand ?? (onClickButtonCommand = new RelayCommand(p => dataCache.AddStringToMessage((string)p)));
}
}
}
public class ButtonsViewModel : ViewModelBase
{
private readonly DataCache dataCache = DataCache.Instance;
private ICommand onGoBackCommand;
public ICommand OnGoBackButton
{
get
{
return onGoBackCommand ?? (onGoBackCommand = new RelayCommand(p => dataCache.ClearMessage()));
}
}
}
public class RelayCommand : ICommand
{
#region Fields
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
#endregion Fields
#region Constructors
public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
var handler = CanExecuteChanged;
if (handler != null) handler(this, EventArgs.Empty);
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion ICommand Members
}
<Window x:Class="StudentScoreWpfProj.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:StudentScoreWpfProj"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=local:MainViewModel,IsDesignTimeCreatable=True}"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<local:MessgaeView DataContext="{Binding MessageViewModel}" />
<local:KeyboardView Grid.Row="1" DataContext="{Binding KeyboardViewModel}" />
<local:ButtonsView Grid.Row="2" DataContext="{Binding ButtonsViewModel}" />
</Grid>
<UserControl x:Class="StudentScoreWpfProj.ButtonsView"
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:local="clr-namespace:StudentScoreWpfProj"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=local:ButtonsViewModel,IsDesignTimeCreatable=True}"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<StackPanel Orientation="Horizontal">
<Button Content="GoBack" Command="{Binding OnGoBackButton}"></Button>
<Button Content="Continue"></Button>
</StackPanel>
</Grid>
<UserControl x:Class="StudentScoreWpfProj.KeyboardView"
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:local="clr-namespace:StudentScoreWpfProj"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=local:KeyboardViewModel,IsDesignTimeCreatable=True}"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<StackPanel Orientation="Horizontal">
<Button Content="A" Command="{Binding OnClickButton}" CommandParameter="A"></Button>
<Button Content="B" Command="{Binding OnClickButton}" CommandParameter="B"></Button>
<Button Content="C" Command="{Binding OnClickButton}" CommandParameter="C"></Button>
</StackPanel>
</Grid>
<UserControl x:Class="StudentScoreWpfProj.MessgaeView"
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:local="clr-namespace:StudentScoreWpfProj"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=local:MessageViewModel,IsDesignTimeCreatable=True}"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBox Text="{Binding Message}"/>
</Grid>
关于c# - 将 ViewModel 引用传递给另一个 ViewModel(绑定(bind)到 View 的同一引用)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32595480/