1)在多个视图之间传递数据的最佳方法是什么?
2)我有场景(MVVM C#):
MainWindow中的TextBox和Button以及Window1中的TextBlock, 在按钮上单击(我正在使用Icommand)MainWindow的TextBox中的数据必须出现在Window1的TextBlock中?
ViewModelBase.cs
public class ViewModelBase
{
public Commandclass commandclass { get; set; }
public ViewModelBase()
{
commandclass = new Commandclass(this);
}
private string fname;
public string vmname
{
get { return fname; }
set { fname = value; }
}
public void OnCommand()
{
Window1 w = new Window1();
/* How to bind ???*/
w.Show();
}
}
CommandClass.cs
public class Commandclass : ICommand
{
public ViewModelBase vmclass { get; set; }
public Commandclass(ViewModelBase vmb)
{
vmclass = vmb;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
vmclass.OnCommand();
}
}
浏览
**MainWindow.xaml**
<Window x:Class="Multiwindow.MainWindow"
…
xmlns:vm="clr-namespace:Multiwindow.Viewmodel">
<Window.Resources>
<vm:ViewModelBase x:Key="vmodel"/>
</Window.Resources>
<Grid Background="Gray" DataContext="{StaticResource vmodel}">
<TextBox Height="26" Margin="194,115,154,179" Width="169"
Text="{Binding vmname, Mode=TwoWay}"/>
<Button Content="Button1" HorizontalAlignment="Left"
Margin="251,158,0,0" VerticalAlignment="Top"
Command="{Binding commandclass, Source={StaticResource vmodel}}"/>
</Grid>
</Window>
**Window1.xaml**
<Window.Resources>
<vm:ViewModelBase x:Key="vmodel"/>
</Window.Resources>
<Grid >
<TextBlock FontSize="20" Height="28" Width="169" Foreground="Black"
Background="Bisque" />
</Grid>
我用谷歌搜索并发现了一个项目,但它是复杂的,请建议我的答案2)问题将有所帮助..谢谢。
答案 0 :(得分:4)
我就是这样做的。在命令按钮上单击按钮,执行以下操作:
Window2 w= new Window2();
w.DataContext=new Window2ViewModel();
((Window2ViewModel)w.DataContext).TextForTextblock=TextFromTextbox;
w.Show();
修改强>
看到您的代码,您可以这样做,因为我认为两个窗口共享ViewModelBase:
Window1 w= new Window1();
w.DataContext=this;
w.Show();
您还必须绑定TextBlock:
<TextBlock FontSize="20" Height="28" Width="169" Foreground="Black"
Background="Bisque" Text="{Binding vmname}"/>
答案 1 :(得分:1)
我假设您打算在MainWindow和Window1之间共享ViewModelBase
。在这种情况下,您无法将ViewModelBase实例添加到MainWindow.Resources,然后将另一个实例添加到Window1.Resources。 如果您没有解释原因,请查看一些C#OOP教程。
要在多个视图之间共享ViewModelBase的同一实例,您必须只创建一个资源。可以从所有视图访问Application.Resource。
就是这样。
但是,建议您为每个View提供单独的ViewModel类。
在这种情况下,你可能会有这样的事情:
<Window x:Class="Multiwindow.MainWindow"
xmlns:vm="clr-namespace:Multiwindow.Viewmodel">
<Window.DataContext>
<vm:MainWindowViewModel />
</Window.DataContext>
...
</Window>
**Window1.xaml**
<Window.DataContext>
<vm:Window1ViewModel />
</Window.Resources>
除了@ Pikoh的解决方案,我建议如下:
构造函数参数:
var window1 = new Window1("hello world");
windows1.Show();
public class Window1(string parameter){...
我在视图上设置了 ViewModel属性,并允许在视图上创建ViemModel的重复性。
var window1 = new Window1();
window1.ViewModel.Parameter = "Hello world";
public class Window1{
...
public Window1ViewModel { get {return (Window1ViewModel)DataContext;}}
}
datacontext应该在ctor或XAML中设置。
ViewModel首次方法:
a)为第二个窗口创建视图模型
b)在viewmodel上设置参数
c)使用自定义DialogService
类根据使用命名约定的viewmodel类型为您创建视图并显示它。
这样你甚至不会触摸视图模型中的任何视图,并且你的视图模型与视图完全分开,因此它很容易测试。运行单元测试时,可以轻松替换DialogService实现。
//in MainWindowViewModel:
var secondWindowViewModel = new SecondWindowViewModel();
//alternativelly:
//secondWindowViewModel = ViewModelLocator.Resolve<SecondWindowViewModel>();
secondWindowViewModel.Parameter = "Hello world";
dialogService.Show(secondWindowViewModel);
答案 2 :(得分:0)
如果要在视图模型之间共享数据,则需要将中介实现应用于您的代码。
请查看here您会找到有关它的更多信息。
答案 3 :(得分:0)
以下是您的问题的完整答案:
主窗口xaml代码
<Window x:Class="TwoWindowsDialogSoHelpAttempt.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:twoWindowsDialogSoHelpAttempt="clr-namespace:TwoWindowsDialogSoHelpAttempt"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<!--Main window data context declaration-->
<twoWindowsDialogSoHelpAttempt:FirstWindowDataContext/>
</Window.DataContext>
<i:Interaction.Behaviors>
<!--next behavior helps to control loading of the second window-->
<twoWindowsDialogSoHelpAttempt:SecondWindowLoadingBehavior
IsSecondWindowShouldBeShown="{Binding IsSecondWindowShouldBeShown, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
CanProvideDataForSecondWindow="{Binding CanProvideDataForSecondWindow, UpdateSourceTrigger=PropertyChanged}"/>
</i:Interaction.Behaviors>
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Border Width="150" Height="30" BorderBrush="Tomato" BorderThickness="1">
<TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</Border>
<Button Command="{Binding Command, UpdateSourceTrigger=PropertyChanged}">Show second Window</Button>
</StackPanel>
</Grid>
第二个窗口xaml代码
<Window x:Class="TwoWindowsDialogSoHelpAttempt.SecondWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SecondWindow" Height="300" Width="300">
<Grid Background="Green">
<TextBlock Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="150"></TextBlock>
</Grid>
第二个窗口加载行为,有助于控制SecondWindow外观,并将ICanProvideDataForSecondWindow注入到第二个窗口视图模型中
public class SecondWindowLoadingBehavior:Behavior<FrameworkElement>
{
private Window _window;
public static readonly DependencyProperty CanProvideDataForSecondWindowProperty = DependencyProperty.Register(
"CanProvideDataForSecondWindow", typeof (ICanProvideDataForSecondWindow), typeof (SecondWindowLoadingBehavior), new PropertyMetadata(default(ICanProvideDataForSecondWindow)));
/// <summary>
/// helps to control dialog between first and second window
/// </summary>
public ICanProvideDataForSecondWindow CanProvideDataForSecondWindow
{
get { return (ICanProvideDataForSecondWindow) GetValue(CanProvideDataForSecondWindowProperty); }
set { SetValue(CanProvideDataForSecondWindowProperty, value); }
}
public static readonly DependencyProperty IsSecondWindowShouldBeShownProperty = DependencyProperty.Register(
"IsSecondWindowShouldBeShown", typeof (bool), typeof (SecondWindowLoadingBehavior), new PropertyMetadata(default(bool), IsSecondWindowShouldBeShownPropertyChangedCallback));
//when the IsSecondWindowShouldBeShown dependency property will be changed, will trigger the window showing
private static void IsSecondWindowShouldBeShownPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
var isShouldBeShown = (bool) args.NewValue;
var behavior = dependencyObject as SecondWindowLoadingBehavior;
if (isShouldBeShown == false || behavior == null || behavior.CanProvideDataForSecondWindow == null)
{
return;
}
behavior.ShowSecondWindow();
}
/// <summary>
/// helps to control the second window loading
/// </summary>
public bool IsSecondWindowShouldBeShown
{
get { return (bool)GetValue(IsSecondWindowShouldBeShownProperty); }
set { SetValue(IsSecondWindowShouldBeShownProperty, value); }
}
//helps to prepare and show the second window
private void ShowSecondWindow()
{
_window = new SecondWindow {DataContext = new SecondWindowDataContext(CanProvideDataForSecondWindow)};
_window.Closing += WindowOnClosing;
_window.Show();
}
//disposes a data context instance when a window was closed
private void WindowOnClosing(object sender, CancelEventArgs e)
{
_window.Closing -= WindowOnClosing;
IsSecondWindowShouldBeShown = false;
var disposableDataContext = _window.DataContext as IDisposable;
if (disposableDataContext == null) return;
disposableDataContext.Dispose();
}
}
查看模型和帮助
主窗口视图模型,实现ICanProvideDataForSecondWindow以便能够动态发送数据并更改第二个窗口内容
/// <summary>
/// a first window data context, provides data to the second window based on a
/// ICanProvideDataForSecondWindow implementation
/// </summary>
public class FirstWindowDataContext:BaseObservableObject, ICanProvideDataForSecondWindow
{
private string _text;
private ICommand _command;
private bool _isSecondWindowShouldBeShown;
private ICanProvideDataForSecondWindow _canProvideDataForSecondWindow;
public FirstWindowDataContext()
{
CanProvideDataForSecondWindow = this;
}
public ICanProvideDataForSecondWindow CanProvideDataForSecondWindow
{
get { return _canProvideDataForSecondWindow; }
set
{
_canProvideDataForSecondWindow = value;
OnPropertyChanged();
}
}
public string Text
{
get { return _text; }
set
{
_text = value;
OnPropertyChanged();
OnSecondWindowDataEventHandler(new DataForSecondWindowArgs{Data = Text});
}
}
public ICommand Command
{
get { return _command ?? (_command = new RelayCommand(ShowSecondWindow)); }
}
//method to show the second window
private void ShowSecondWindow()
{
//will show the window if it isn't opened yet
if(IsSecondWindowShouldBeShown) return;
IsSecondWindowShouldBeShown = true;
}
public bool IsSecondWindowShouldBeShown
{
get { return _isSecondWindowShouldBeShown; }
set
{
_isSecondWindowShouldBeShown = value;
OnPropertyChanged();
}
}
public event EventHandler<DataForSecondWindowArgs> SecondWindowDataEventHandler;
protected virtual void OnSecondWindowDataEventHandler(DataForSecondWindowArgs e)
{
var handler = SecondWindowDataEventHandler;
if (handler != null) handler(this, e);
}
}
ICanProvideDataForSecondWindow - 帮助主要和第二个窗口视图模型之间进行通信的界面
public interface ICanProvideDataForSecondWindow
{
event EventHandler<DataForSecondWindowArgs> SecondWindowDataEventHandler;
string Text { get; set; }
}
DataForSecondWindowArgs - 在视图模型通信期间传递的参数
public class DataForSecondWindowArgs:EventArgs
{
public string Data { get; set; }
}
SecondWindow数据上下文 - 是侦听器,通过ICanProvideDataForSecondWindow接口获取数据。
/// <summary>
/// second window data context, listening for the changes in first window data context to show them on the second window
/// </summary>
class SecondWindowDataContext:DisposableBaseObservableObject
{
private readonly ICanProvideDataForSecondWindow _canProvideDataForSecondWindow;
private string _text;
public SecondWindowDataContext(ICanProvideDataForSecondWindow canProvideDataForSecondWindow)
{
_canProvideDataForSecondWindow = canProvideDataForSecondWindow;
_canProvideDataForSecondWindow.SecondWindowDataEventHandler += CanProvideDataForSecondWindowOnSecondWindowDataEventHandler;
Text = _canProvideDataForSecondWindow.Text;
}
private void CanProvideDataForSecondWindowOnSecondWindowDataEventHandler(object sender, DataForSecondWindowArgs args)
{
Text = args.Data;
}
public string Text
{
get { return _text; }
set
{
_text = value;
OnPropertyChanged();
}
}
protected override void DisposeOverride()
{
base.DisposeOverride();
_canProvideDataForSecondWindow.SecondWindowDataEventHandler -= CanProvideDataForSecondWindowOnSecondWindowDataEventHandler;
}
}
INPC实现和命令(您可以将其替换为您自己的Commandclass)代码
/// <summary>
/// implements the INotifyPropertyChanged (.net 4.5)
/// </summary>
public class DisposableBaseObservableObject : INotifyPropertyChanged, IDisposable
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> raiser)
{
var propName = ((MemberExpression)raiser.Body).Member.Name;
OnPropertyChanged(propName);
}
protected bool Set<T>(ref T field, T value, [CallerMemberName] string name = null)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
OnPropertyChanged(name);
return true;
}
return false;
}
#region Disposable
private bool _isDisposed;
~DisposableBaseObservableObject()
{
Dispose();
}
public void Dispose()
{
if (_isDisposed)
{
return;
}
GC.SuppressFinalize(this);
_isDisposed = true;
DisposeOverride();
}
protected virtual void DisposeOverride()
{
}
#endregion
}
public class RelayCommand : ICommand
{
private readonly Func<bool> _canExecute;
private readonly Action _execute;
public RelayCommand(Action execute)
: this(() => true, execute)
{
}
public RelayCommand(Func<bool> canExecute, Action execute)
{
_canExecute = canExecute;
_execute = execute;
}
public bool CanExecute(object parameter = null)
{
return _canExecute();
}
public void Execute(object parameter = null)
{
_execute();
}
public event EventHandler CanExecuteChanged;
}
<强>说明强>
如果需要,我很乐意帮助提供其他解释。 请告诉我。
问候。