惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
Microsoft Security Blog
Microsoft Security Blog
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI
罗磊的独立博客
腾讯CDC
云风的 BLOG
云风的 BLOG
月光博客
月光博客
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 三生石上(FineUI控件)
宝玉的分享
宝玉的分享
U
Unit 42
I
InfoQ
D
DataBreaches.Net
Blog — PlanetScale
Blog — PlanetScale
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
V2EX
美团技术团队
IT之家
IT之家
Stack Overflow Blog
Stack Overflow Blog
F
Fortinet All Blogs
GbyAI
GbyAI
S
SegmentFault 最新的问题

博客园 - 天神一

Windows 8的本地化应用程序清单 代码滑动panorama-即程序中设置SelectedIndex WP7开发 Sqlite数据库的使用 解决Unable open the database WP7 真机调试PhotoChooserTask和CameraCaptureTask 解决windows8不能安装ZUNE的问题 软件概要设计 AutoResetEvent详解 解决VS2008 调试启动特别慢 微软WP7本地数据库之Sqlite编程技巧(转) 桥接模式的简单分析 代码的“门面”——模式系列谈之Facade模式(转) SilverLight4:在MVVM架构下实现模式窗口 简析SilverLight的List<T>、ObservableCollection<T>和INotifyPropertyChanged的异同 MVVM架构的简单解析 在MVVM架构下,把EventArgs绑定到Command上【翻译】 XNA 4.0新书:初学者很好的书籍 SilverLight:在MVVM中实现多事件 SilverLight:使用MVVM实现View层在程序运行时自动生成控件并且取得其值 Windows Phone 7 完全版电子书可以免费下载了
(翻译)在MVVM模式中打开子窗体(Child Window)
天神一 · 2010-12-08 · via 博客园 - 天神一

  这篇文章主要展示在Silverlight4的应用程序中,用MVVM模式【编者注:如果你对MVVM模式不太理解,请先去熟悉一下关于这方面的资料】怎么打开一个子窗体(Child Window),怎么向子窗体传值,以及怎么从子窗体返回值到主窗体等等

  我使用的方法不是严格意义上的MVVM模式,因为我实际上在ViewModel中实例化了子窗体,这通常很不方便的。但是在Google上找了好长时间,仅仅找到了打开子窗体的工具包的向导,我认为最好的方法就是亲自去实现它。我期望最方便且有严格意义上的MVVM的解决方案在SilverLight5中能够实现。

  本篇文章只仅仅是一个概念的验证,并且是基于一个最简单的例子。MainPage.xaml文件包含两个TextBox控件,即Name和Address,另外,子窗体和主窗体一样,也有两个的控件。当用户在主窗体输入他们的名字,然后点击按钮,那么子窗体就弹出来。并且显示刚才输入的名字(请看下面的图片)。用户可以在子窗体中输入地址然后点击按钮,返回到主窗体【编者注:子窗体同时关闭】,那么主窗体上的地址框中就会显示刚才在子窗体中输入的地址。【编者注:这样就可以达到主窗体和子窗体之间互相传值】

  实现上面的功能是很简单的,仅仅在View Model工程中创建一个子窗体。然后就可以实现子窗体和主窗体之间传递数据。然后创建每一个TextBox建一个属性,为Button创建Command,这是为了打开和关闭子窗体并且传递属性值。需要注意的是子窗体没有ViewModel,所有的需要实现的业务都在主窗体的ViewModel中实现

  第一步:在ViewModel工程中创建一个子窗体,把它命名为MyChildWindow.xmal.

  第二步:为MainPage创建一个ViewModel层。命名为:MainPage_ViewModel.cs

  第三步:通过MainPage_ViewModel.cs来实现 MainPage.xaml.cs和MyChildWindow.xaml.cs 相互传值。【编者注:下面为各个文件的代码】

  MainPage.xaml.cs:

代码

namespace View
{
    
public partial class MainPage : UserControl
    {
public MainPage()
        {
            InitializeComponent();
            
this.DataContext = new MainPage_ViewModel();
         }
     }
}

 MyChildWindow.xaml.cs:

代码

namespace ViewModel
{
    
public partial class MyChildWindow : ChildWindow
    {
        
public MyChildWindow(MainPage_ViewModel ma)
        {
            InitializeComponent();
            
this.DataContext = ma;
        }

    }
}

  第四步:在 MainPage_ViewModel.cs为主窗体每个TextBox建属性和ViewModel

代码

using System.ComponentModel;
using System.Collections.ObjectModel;
using ViewModel; namespace ViewModel
{
    
public class MainPage_ViewModel : INotifyPropertyChanged
    {
//Properties of Mainpage
private string myNameVM = "";
        
public string MyNameVM
        {
get { return myNameVM; }
            
set {
                myNameVM 
= value;
                RaisePropertyChanged(
"myNameVM");
            }
        }
private string myAddressVM = "";
        
public string MyAddressVM
        {
get { return myAddressVM; }
            
set
            {
                myAddressVM 
= value;
                RaisePropertyChanged(
"MyAddressVM");
            }
        }
//Properties of ChildWindow
        private string myNameCW = "";
        
public string MyNameCW
        {
get { return myNameCW; }
            
set
            {
                myNameCW 
= value;
                RaisePropertyChanged(
"MyNameCW");
            }
        }
private string myAddressCW = "";
        
public string MyAddressCW
        {
get { return myAddressCW; }
            
set
            {
                myAddressCW 
= value;
                RaisePropertyChanged(
"MyAddressCW");
            }
        }
//EventHandler
        public event PropertyChangedEventHandler PropertyChanged;
        
private void RaisePropertyChanged(string propertyname)
        {
            
if (PropertyChanged != null)
            {
                PropertyChanged(
thisnew PropertyChangedEventArgs(propertyname));
            }
        }
    }

 }

  第五步:如果以前没有创建这个,你就必须得在ViewModel中创建一个类DelegateCommand,主要是处理Button的命令。因此,你必须创建这个类。代码如下:

代码

using System;
using System.Windows.Input;namespace ViewModel
{
    
public class DelegateCommand : ICommand //
    {
        
private Predicate<object> _canExecute;
        
private Action<object> _method;
        
public event EventHandler CanExecuteChanged;public DelegateCommand(Action<object> method)
            : 
this(method, null)
        {
        }
public DelegateCommand(Action<object> method, Predicate<object> canExecute)
        {
            _method 
= method;
            _canExecute 
= canExecute;
        }
public bool CanExecute(object parameter)
        {
            
if (_canExecute == null)
            {
                
return true;
            }
return _canExecute(parameter);
        }
public void Execute(object parameter)
        {
            _method.Invoke(parameter);
        }
protected virtual void OnCanExecuteChanged(EventArgs e)
        {
            var canExecuteChanged 
= CanExecuteChanged;if (canExecuteChanged != null)
                canExecuteChanged(
this, e);
        }
public void RaiseCanExecuteChanged()
        {
            OnCanExecuteChanged(EventArgs.Empty);
        }
    }
}

  第六步:在MainPage_ViewModel.cs创建一个Commands,它可以绑定到主窗体和子窗体中的按钮上

代码

using System.ComponentModel;
using
 System.Collections.ObjectModel;
using
 ViewModel; namespace ViewModel
{
    
public class
 MainPage_ViewModel : INotifyPropertyChanged
    {
//Properties of Mainpage

private string myNameVM = "";
        
public string
 MyNameVM
        {
            
get { return
 myNameVM; }
            
set {myNameVM =
 value;
                RaisePropertyChanged(
"myNameVM"
);
                 }
            }
private string myAddressVM = ""
;
        
public string
 MyAddressVM
        {
get { return
 myAddressVM; }
            
set

            { myAddressVM 
= value;
                RaisePropertyChanged(
"MyAddressVM"
);
            }
        }
//Properties of ChildWindow

        private string myNameCW = "";
        
public string
 MyNameCW
        {
get { return
 myNameCW; }
            
set

            {  myNameCW 
= value;
                RaisePropertyChanged(
"MyNameCW"
);
            }
        }
private string myAddressCW = ""
;
        
public string
 MyAddressCW
        {
get { return
 myAddressCW; }
            
set

            {  myAddressCW 
= value;
                RaisePropertyChanged(
"MyAddressCW"
);
            }
        }
//When the button is pressed in MainPage, executes method ExecuteOpenChildWindow

        private DelegateCommand _openChildWindow;
        
public
 DelegateCommand OpenChildWindow
        {
            
get

            {
                
if (_openChildWindow == null)
                    _openChildWindow 
= new
 DelegateCommand(executeOpenChildWindow);return _openChildWindow;
            }
        }
// New instance of ChildWindow. Sets the NameProperty of the ChildWindow equal to the Name entered in the MainPage.

        MyChildWindow cw;
        
private void executeOpenChildWindow(object
 parameter)
        {
            cw 
= new MyChildWindow(this
);
            MyNameCW 
=
 MyNameVM;
            cw.Show();
        }
//When OK-button is pressed in ChildWindow

        private DelegateCommand _okChildWindow;
        
public
 DelegateCommand OkChildWindow
        {
            
get
 {
                
if (_okChildWindow == null
)
                    _okChildWindow 
= new
 DelegateCommand(OkSaveChildWindow);return _okChildWindow;
            }
        }
        
//MainPage Address property is set to the value entered in the address textbox in Child Window. Child Window is closed.

        private void OkSaveChildWindow(object parameter)
        {
            MyAddressVM 
=
 MyAddressCW;
            cw.Close();
        }
//EventHandler

        public event PropertyChangedEventHandler PropertyChanged;
        
private void RaisePropertyChanged(string
 propertyname)
        {
            
if (PropertyChanged != null
)
            {
                PropertyChanged(
thisnew
 PropertyChangedEventArgs(propertyname));
            }
        }
  }
}

  第七步:在MainPage.xaml 和 MyChildWindow.xaml中分别新增两个TextBox,然后把他们分别绑定到MainPage_ViewModel中的属性上。然后再分别建一个按钮,绑定到Command上

MainPage.xaml

代码

<StackPanel><Grid Margin="0 10 0 5" Width="350"><Grid.RowDefinitions>
        
<RowDefinition Height="*"/>
        
<RowDefinition Height="*"/>
        
<RowDefinition Height="*"/></Grid.RowDefinitions>
    
<Grid.ColumnDefinitions>
        
<ColumnDefinition Width="150"/>
        
<ColumnDefinition Width="*"/></Grid.ColumnDefinitions><!--TextBlocks-->
    
<TextBlock Text="Name:" TextWrapping="Wrap" Margin="5,5,0,5" Grid.Row="0"  />
    
<TextBlock Text="Address:" Grid.Row="1" Grid.Column="0"  /><!--TextBox, where the users enters data. Binds to the properties of MainPage_ViewModel-->
  
<TextBox Text="{Binding MyNameVM, Mode=TwoWay}" Grid.Row="0" Grid.Column="1"/>
  
<TextBox Text="{Binding MyAddressVM, Mode=TwoWay}"  Grid.Row="1" Grid.Column="1"/><Button Content="Open Child Window"
            VerticalAlignment
="Center"
            HorizontalAlignment
="left"
            Width
="auto"
            Margin
="5"
            Grid.Row
="2"
            Command
="{Binding OpenChildWindow}" <!--Binds to CommandDelegate from the ViewModel -->
        
/>
        
</Grid>
    
</StackPanel>

MyChildWindow.xaml

代码

<Grid Margin="0 30 0 5" Width="350"><Grid.RowDefinitions>
        
<RowDefinition Height="auto"/>
        
<RowDefinition Height="auto"/>
        
<RowDefinition Height="205*"/></Grid.RowDefinitions>
    
<Grid.ColumnDefinitions>
        
<ColumnDefinition Width="150"/>
        
<ColumnDefinition Width="*"/></Grid.ColumnDefinitions><TextBlock Text="Name: " Grid.Row="0" />
    
<TextBlock Text="Address:" Grid.Row="1" Grid.Column="0"  /><!-- TextBoxes are bind to the properties from the ViewModel.  -->
    
<TextBox x:Name="InputName" Text="{Binding MyNameCW, Mode=TwoWay}" Grid.Row="0" Grid.Column="1" Height="20"/>
    
<TextBox x:Name="OutputAddress" Text="{Binding MyAddressCW, Mode=TwoWay}" Grid.Row="1" Grid.Column="1" Height="20"/><!-- Button comand bind to CommandDelegate from ViewModel -->
  
<Button x:Name="OKButton" Command="{Binding OkChildWindow}" Content="OK" Width="75" Height="23" Margin="0,12,79,0" Grid.Row="2" Grid.Column="1"/>
</Grid>

  翻译的不足之处,请多多指教。原文地址http://mariaevert.dk/thesis/?p=710