【MVVM】请问如何在ViewModel中访问View中的控件?

aday 2014-09-12 04:39:26
View只负责UI部分,假设有一个TextBox控件,Name为myText
ViewModel负责功能部分,在cs代码中如何访问View中的mtText呢?比如要让mtText获得焦点
...全文
3729 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
vbfool 2014-09-16
  • 打赏
  • 举报
回复
引用 15 楼 aday 的回复:
[quote=引用 14 楼 vbfool 的回复:] TabControl也是可以绑定集合的,这些操作都可以在ViewModel里完成。 你说的获得焦点之类的,都是可以通过自己写Behavior和TriggerAction来进行封装的。
非常感谢,就是你说的这个,能不能给个简单的例子或者有没有相关的资料,我折腾MVVM好几天了,就是卡在这里了。 另外我看SimpleMVVM的官方例子(最新版),发现View的cs文件写有很多按钮的事件,我觉得这样做把MVVM的概念搞混乱了,是否应该把View中的事件代码放在ViewModel中来处理更合理呢?[/quote] View本身是一层,在里边写代码其实也无可厚非(只跟UI有关的代码),不过我觉得还是封起来比较好。 Behavior的例子:

 public class CloseWindowAction : TriggerAction<System.Windows.DependencyObject>
    {
        protected override void Invoke(object parameter)
        {
            var w = System.Windows.Window.GetWindow(AssociatedObject);
            if (w != null)
            {
                w.Close();
            }
        }
    }

    public class WindowClosingBehavior : Behavior<System.Windows.Window>
    {
        protected override void OnAttached()
        {
            AssociatedObject.Closing += AssociatedObject_Closing;
            base.OnAttached();
        }

        void AssociatedObject_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            e.Cancel = (MessageBox.Show("确定要退出么?", AssociatedObject.Title, MessageBoxButton.OKCancel, MessageBoxImage.Warning) == MessageBoxResult.Cancel);
        }
        protected override void OnDetaching()
        {
            AssociatedObject.Closing -= AssociatedObject_Closing;
            base.OnDetaching();
        }
    }

    public class ExitApplicationBehavior : Behavior<System.Windows.Window>
    {
        protected override void OnAttached()
        {
            AssociatedObject.Closed += AssociatedObject_Closed;
            base.OnAttached();
        }

        void AssociatedObject_Closed(object sender, EventArgs e)
        {
            Application.Current.Shutdown();
        }


        protected override void OnDetaching()
        {
            AssociatedObject.Closed -= AssociatedObject_Closed;
            base.OnDetaching();
        }
    }
chunjiang8257 2014-09-16
  • 打赏
  • 举报
回复
建议你可以看看刘铁猛的视频"MVVM入门与提高"(http://v.youku.com/v_show/id_XMzMyMjg4NTQ0.html),感觉讲得挺清晰的。
E次奥 2014-09-16
  • 打赏
  • 举报
回复
这个直接在View中写个Trigger就可以解决
aday 2014-09-15
  • 打赏
  • 举报
回复
引用 2 楼 duanzi_peng 的回复:
ViewModel中访问View中的控件 那还叫 MVVM了吗????
嗯,我是按照传统的方法来理解MVVM,肯定不正确,所以才提出传统的方法在MVVM中应该怎么做?具体的例子就是#1楼中提到的
exception92 2014-09-15
  • 打赏
  • 举报
回复
ViewModel中访问View中的控件 那还叫 MVVM了吗????
aday 2014-09-15
  • 打赏
  • 举报
回复
引用 14 楼 vbfool 的回复:
TabControl也是可以绑定集合的,这些操作都可以在ViewModel里完成。 你说的获得焦点之类的,都是可以通过自己写Behavior和TriggerAction来进行封装的。
非常感谢,就是你说的这个,能不能给个简单的例子或者有没有相关的资料,我折腾MVVM好几天了,就是卡在这里了。 另外我看SimpleMVVM的官方例子(最新版),发现View的cs文件写有很多按钮的事件,我觉得这样做把MVVM的概念搞混乱了,是否应该把View中的事件代码放在ViewModel中来处理更合理呢?
vbfool 2014-09-15
  • 打赏
  • 举报
回复
引用 13 楼 aday 的回复:
[quote=引用 10 楼 chunjiang8257 的回复:] "我看了好几个Mvvm构架也是这样操作的,但这样做的问题就来了,View里面既有UI,又有代码,那么ViewModel的意义何在? 我再举个例子,View是有1个Grid、1个TextBox、1个Button,Button绑定了ViewModel的ButtonClick事件,现要求Button点击之后,处理以下几件事情: 1、Grid根据TextBox的值重新进行查询(实际上后端SQL就是LIKE查询) 2、TextBox获得焦点 请问这个View和ViewModel该怎么写呢?" MVVM模式目标并不是为了让UI后台完全没有代码的。使用MVVM后各层职责划分更清晰,实现解耦,应对变化(UI是最容易变化的)。实现MVVM后,ui的后台代码基本都是UI操作相关的。 你的例子里 1、ViewModel层的设置两个属性,一个用于绑定TEXTBOX的值,一个用于DataGrid的数据源。 2、Button Command 绑定到VM层的BtnViewCommand(ViewCommand类型) 3、在ViewModel添加BtnViewCommand.Action用于处理数据查询。 4、在View的后台代码里添加一个Action用于处理TextBox的焦点事件。
嗯,步骤明白了,现在的问题就在3和4 实际上第3步我也明白了,也就是在View中绑定数据源就可以 但是第4步我不知道该如何操作,因为这里我使用的控件没有焦点属性,也就无法绑定,但是可以通过代码来设置焦点(Text.Focus()),我这里只是举一个简单的例子,实际上要比这个复杂 比如Tab页,当我点击某个按钮时(按钮绑定ViewModel的事件),Tab会先判断该页是否生成,如果生成,就让这页Active,如果没有生成,则Add,并Active,这个过程中,ViewModel的这个按钮事件就需要对Tab进行遍历(判断是否已经生成和Active),那么ViewModel中如何访问View中的这个Tab,这就是我的核心问题。[/quote] TabControl也是可以绑定集合的,这些操作都可以在ViewModel里完成。 你说的获得焦点之类的,都是可以通过自己写Behavior和TriggerAction来进行封装的。
aday 2014-09-15
  • 打赏
  • 举报
回复
引用 10 楼 chunjiang8257 的回复:
"我看了好几个Mvvm构架也是这样操作的,但这样做的问题就来了,View里面既有UI,又有代码,那么ViewModel的意义何在? 我再举个例子,View是有1个Grid、1个TextBox、1个Button,Button绑定了ViewModel的ButtonClick事件,现要求Button点击之后,处理以下几件事情: 1、Grid根据TextBox的值重新进行查询(实际上后端SQL就是LIKE查询) 2、TextBox获得焦点 请问这个View和ViewModel该怎么写呢?" MVVM模式目标并不是为了让UI后台完全没有代码的。使用MVVM后各层职责划分更清晰,实现解耦,应对变化(UI是最容易变化的)。实现MVVM后,ui的后台代码基本都是UI操作相关的。 你的例子里 1、ViewModel层的设置两个属性,一个用于绑定TEXTBOX的值,一个用于DataGrid的数据源。 2、Button Command 绑定到VM层的BtnViewCommand(ViewCommand类型) 3、在ViewModel添加BtnViewCommand.Action用于处理数据查询。 4、在View的后台代码里添加一个Action用于处理TextBox的焦点事件。
嗯,步骤明白了,现在的问题就在3和4 实际上第3步我也明白了,也就是在View中绑定数据源就可以 但是第4步我不知道该如何操作,因为这里我使用的控件没有焦点属性,也就无法绑定,但是可以通过代码来设置焦点(Text.Focus()),我这里只是举一个简单的例子,实际上要比这个复杂 比如Tab页,当我点击某个按钮时(按钮绑定ViewModel的事件),Tab会先判断该页是否生成,如果生成,就让这页Active,如果没有生成,则Add,并Active,这个过程中,ViewModel的这个按钮事件就需要对Tab进行遍历(判断是否已经生成和Active),那么ViewModel中如何访问View中的这个Tab,这就是我的核心问题。
aday 2014-09-15
  • 打赏
  • 举报
回复
引用 8 楼 sunny906 的回复:
在view里绑定focused,在viewmodel里修改focused,通过通知的功能实现textbox获取焦点或失去焦点

Focusable="{Binding focused}"
假设我用的不是TextBox,而是某个第三方控件的Text,这个控件在XAML中是没有Focusable属性的,但在代码中却能设置Text.Focus();
chunjiang8257 2014-09-15
  • 打赏
  • 举报
回复
当然也可以在vm层添加一个属性,用于textbox 的焦点属性绑定,这样只要在ViewModel层数据查询结束后改变这个属性就可以了。
chunjiang8257 2014-09-15
  • 打赏
  • 举报
回复
"我看了好几个Mvvm构架也是这样操作的,但这样做的问题就来了,View里面既有UI,又有代码,那么ViewModel的意义何在? 我再举个例子,View是有1个Grid、1个TextBox、1个Button,Button绑定了ViewModel的ButtonClick事件,现要求Button点击之后,处理以下几件事情: 1、Grid根据TextBox的值重新进行查询(实际上后端SQL就是LIKE查询) 2、TextBox获得焦点 请问这个View和ViewModel该怎么写呢?" MVVM模式目标并不是为了让UI后台完全没有代码的。使用MVVM后各层职责划分更清晰,实现解耦,应对变化(UI是最容易变化的)。实现MVVM后,ui的后台代码基本都是UI操作相关的。 你的例子里 1、ViewModel层的设置两个属性,一个用于绑定TEXTBOX的值,一个用于DataGrid的数据源。 2、Button Command 绑定到VM层的BtnViewCommand(ViewCommand类型) 3、在ViewModel添加BtnViewCommand.Action用于处理数据查询。 4、在View的后台代码里添加一个Action用于处理TextBox的焦点事件。
chunjiang8257 2014-09-15
  • 打赏
  • 举报
回复
引用 1 楼 aday 的回复:
查了很多资料,发现这方面的介绍很少,而且即使提到,也说得很笼统,没有详细的操作方法。 可能我的问题不是描述的很清楚,我举个很简单的例子: 比如一个按钮,当点击之后,按钮(bSubmit)和文本框(tName)的IsEnabled = false,ViewModel中应该如何写? 另外, 1、View是否应该写代码? 2、ViewModel是否应该读取View中的资源(比如控件),如果不应该,那么当执行某个Command之后,View中所产生的变化应该如何操作(比如上面的例子)?
这个可以通过让Button 绑定ViewCommand类的RelayCommand属性,再在Window的后台代码里实现ui操作部分,然后通过ViewCommand的Action关联操作。
引用 6 楼 aday 的回复:
如果xaml中没有的属性就不知道如何绑定了。
是什么意思?
sunny906 2014-09-15
  • 打赏
  • 举报
回复
在view里绑定focused,在viewmodel里修改focused,通过通知的功能实现textbox获取焦点或失去焦点

Focusable="{Binding focused}"
aday 2014-09-15
  • 打赏
  • 举报
回复
引用 5 楼 chunjiang8257 的回复:
我用的MvvmLight框架(prism也是类似的),自己封装了一个ViewCommand类用于处理UI。以主窗口的关闭和注销命令为例,供参考: 1、ViewModel层的实现 public class MainWindowViewModel : ViewModelBase { public MainWindowViewModel() { CloseViewCommand = new ViewCommand(); LogoutViewCommand = new ViewCommand(); } /// <summary> /// 关?闭À?视º¨®图ª?命¨¹令¢? /// </summary> public ViewCommand CloseViewCommand { get; set; } /// <summary> /// 注Á¡é销¨²是º?视º¨®图ª?命¨¹令¢? /// </summary> public ViewCommand LogoutViewCommand { get; set; } } 2、View层的实现 1)XAML代码 <Button Name="btnAppQuit" ToolTip="退出" Command="{BindinCloseViewCommand.Command}" /> 2)后台代码 /// <summary> /// MainWindow.xaml 的Ì?交?互£¤逻?辑- /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); MainWindowViewModel mainWindowViewModel = new MainWindowViewModel(); mainWindowViewModel.LogoutViewCommand.Action += new Action(LogoutFunc); mainWindowViewModel.CloseViewCommand.Action += new Action(CloseFunc); this.DataContext = mainWindowViewModel; } /// <summary> /// 注Á¡é销¨²方¤?法¤¡§ /// </summary> private void LogoutFunc() { Application.Current.Shutdown(); Thread thread = new Thread(new ThreadStart(() => { string path = AppDomain.CurrentDomain.BaseDirectory + "***.exe"; Process.Start(path); })); thread.Start(); } /// <summary> /// 退ª?出?程¨¬序¨°方¤?法¤¡§ /// </summary> private void CloseFunc() { var result=MessageBox.Show("确¨¡¤认¨?退ª?出?系¦Ì统ª3?ê?", "提¬¨¢示º?", MessageBoxButton.OKCancel, MessageBoxImage.Information); if (result==MessageBoxResult.OK) { Application.Current.Shutdown(); } else { return; } } } 3、ViewCommand类 /// <summary> /// 封¤a装Á¡ã视º¨®图ª?相¨¤关?命¨¹令¢? /// </summary> public class ViewCommand { public string Name { get; set; } public RelayCommand Command { get; set; } public Action Action { get; set; } public ViewCommand():this(string.Empty) { } public ViewCommand(string name) { Name = name; Command = new RelayCommand(() => { ActionFunc(Action); }); } private void ActionFunc(Action action) { if (action != null) { action.Invoke(); } } }
我看了好几个Mvvm构架也是这样操作的,但这样做的问题就来了,View里面既有UI,又有代码,那么ViewModel的意义何在? 我再举个例子,View是有1个Grid、1个TextBox、1个Button,Button绑定了ViewModel的ButtonClick事件,现要求Button点击之后,处理以下几件事情: 1、Grid根据TextBox的值重新进行查询(实际上后端SQL就是LIKE查询) 2、TextBox获得焦点 请问这个View和ViewModel该怎么写呢? 真心求教,还望详解,非常感谢!
aday 2014-09-15
  • 打赏
  • 举报
回复
引用 4 楼 vbfool 的回复:
首先,IsEnabled属性是个可以绑定的属性,你写一个bool的属性在ViewModel里,View绑定这个属性,就可以操作它们的IsEnabled了,又不是只有Text属性才可以绑定。 对于MVVM,很多时候需要加载Blend的几个库,实现几个Behavior和TriggerAction,把一些不能直接操作的和View交互的东西都封装在这里。
这个我会用,不过只是一些简单的绑定,如果xaml中没有的属性就不知道如何绑定了。
chunjiang8257 2014-09-15
  • 打赏
  • 举报
回复
我用的MvvmLight框架(prism也是类似的),自己封装了一个ViewCommand类用于处理UI。以主窗口的关闭和注销命令为例,供参考: 1、ViewModel层的实现 public class MainWindowViewModel : ViewModelBase { public MainWindowViewModel() { CloseViewCommand = new ViewCommand(); LogoutViewCommand = new ViewCommand(); } /// <summary> /// 关?闭À?视º¨®图ª?命¨¹令¢? /// </summary> public ViewCommand CloseViewCommand { get; set; } /// <summary> /// 注Á¡é销¨²是º?视º¨®图ª?命¨¹令¢? /// </summary> public ViewCommand LogoutViewCommand { get; set; } } 2、View层的实现 1)XAML代码 <Button Name="btnAppQuit" ToolTip="退出" Command="{BindinCloseViewCommand.Command}" /> 2)后台代码 /// <summary> /// MainWindow.xaml 的Ì?交?互£¤逻?辑- /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); MainWindowViewModel mainWindowViewModel = new MainWindowViewModel(); mainWindowViewModel.LogoutViewCommand.Action += new Action(LogoutFunc); mainWindowViewModel.CloseViewCommand.Action += new Action(CloseFunc); this.DataContext = mainWindowViewModel; } /// <summary> /// 注Á¡é销¨²方¤?法¤¡§ /// </summary> private void LogoutFunc() { Application.Current.Shutdown(); Thread thread = new Thread(new ThreadStart(() => { string path = AppDomain.CurrentDomain.BaseDirectory + "***.exe"; Process.Start(path); })); thread.Start(); } /// <summary> /// 退ª?出?程¨¬序¨°方¤?法¤¡§ /// </summary> private void CloseFunc() { var result=MessageBox.Show("确¨¡¤认¨?退ª?出?系¦Ì统ª3?ê?", "提¬¨¢示º?", MessageBoxButton.OKCancel, MessageBoxImage.Information); if (result==MessageBoxResult.OK) { Application.Current.Shutdown(); } else { return; } } } 3、ViewCommand类 /// <summary> /// 封¤a装Á¡ã视º¨®图ª?相¨¤关?命¨¹令¢? /// </summary> public class ViewCommand { public string Name { get; set; } public RelayCommand Command { get; set; } public Action Action { get; set; } public ViewCommand():this(string.Empty) { } public ViewCommand(string name) { Name = name; Command = new RelayCommand(() => { ActionFunc(Action); }); } private void ActionFunc(Action action) { if (action != null) { action.Invoke(); } } }
vbfool 2014-09-15
  • 打赏
  • 举报
回复
首先,IsEnabled属性是个可以绑定的属性,你写一个bool的属性在ViewModel里,View绑定这个属性,就可以操作它们的IsEnabled了,又不是只有Text属性才可以绑定。 对于MVVM,很多时候需要加载Blend的几个库,实现几个Behavior和TriggerAction,把一些不能直接操作的和View交互的东西都封装在这里。
aday 2014-09-13
  • 打赏
  • 举报
回复 1
查了很多资料,发现这方面的介绍很少,而且即使提到,也说得很笼统,没有详细的操作方法。 可能我的问题不是描述的很清楚,我举个很简单的例子: 比如一个按钮,当点击之后,按钮(bSubmit)和文本框(tName)的IsEnabled = false,ViewModel中应该如何写? 另外, 1、View是否应该写代码? 2、ViewModel是否应该读取View中的资源(比如控件),如果不应该,那么当执行某个Command之后,View中所产生的变化应该如何操作(比如上面的例子)?

8,735

社区成员

发帖
与我相关
我的任务
社区描述
WPF/Silverlight相关讨论
社区管理员
  • WPF/Silverlight社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧