关于在MVVM架构下WPF中UserControl的 visibility Binding问题。 UserControl MVVM

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于在MVVM架构下WPF中UserControl的 visibility Binding问题。 UserControl MVVM相关的知识,希望对你有一定的参考价值。

我在ViewModel中用一个枚举来定义页面状态,根据状态控制界面中的UserControl的显隐:
ViewModel:

类似的还有其他三个属性ChatEnabled、UserInfoEnabled、GroupMebEnabled,我通过控制MainState来控制界面UserControl的显隐:

之前我也是这样做的,不过控制的是普通界面元素的显隐(如Button,Textbook等),但是我发现同样的方法用在UserControl上就不管用了(结果是全部显示)。我在DeBug下看过XAML中的变量:

为什么没有效果呢?

参考技术A

usercontrol如果不指定绑定,默认的是uc中的VM,需要指定要绑定的page的vm。

如:

<mycontrols:TimePicker VerticalAlignment="Center" Visibility="Binding DataContext.IsShowTimeUI,Converter=StaticResource BoolToVisibilityCollapseConverter,RelativeSource=RelativeSource FindAncestor,AncestorType=x:Type Page" Width="100" Height="30"></mycontrols:TimePicker>

这句代码表示绑定到父page的datacontext上。如果直接写,Binding IsShowTimeUI,肯定是不起作用的。

参考技术B 应该主要是DataContext不一致吧。绑定到的属性是在主页面的vm里定义还是uc的vm里呢?本回答被提问者和网友采纳 参考技术C

外面包一个层<Grid Visibility=Binding ChatEnabled>这里放用户控件</Grid>

你可以用转换器,设置一个变量,多个状态,根据不同状态选择显示不同界面。

比如 变量1A,B,C

    public class AccountStatusToVisibility : IValueConverter
    
        #region "IValueConverter Members"

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        
            if (value == null)
            
                return Visibility.Collapsed;
            

            if (parameter != null)
            

                var p = parameter.ToString();
                if (p.Contains(","))
                    return p.Split(',').Contains(value.ToString(), StringComparer.OrdinalIgnoreCase) ? Visibility.Visible : Visibility.Collapsed;
                return string.Equals(p, value.ToString(), StringComparison.OrdinalIgnoreCase) ? Visibility.Visible : Visibility.Collapsed;
            

            return Visibility.Collapsed;
        

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        
            throw new NotImplementedException();
        

        #endregion
    

<Grid Visibility="Binding Path=变量1,Converter=StaticResource ToVisibility,ConverterParameter='A'"</Grid>

MVVM 架构 WPF

【中文标题】MVVM 架构 WPF【英文标题】:MVVM architecture WPF 【发布时间】:2016-06-29 04:39:48 【问题描述】:

我对 WPF 中的 MVVM 有一点架构问题。我有View,其中包含编写一些代码或使用computers camera. If user choose to not scan the code, I can bindCommand 扫描QRCode 的选项,没有问题。

用户选择扫描二维码时出现问题。 当用户按下扫描代码时,屏幕的一部分被折叠并且相机显示在屏幕上。我必须在 View 后面的代码中执行此操作,所以我在 View 中得到的代码在 MVVM 中不好。

View 的代码如下所示:

private void Scan_Click(object sender, RoutedEventArgs e)
        
            if (_finalVideo.IsRunning)
            
                _finalVideo.Stop();
            

            _finalVideo = new VideoCaptureDevice(_cameraDevices[CamerasList.SelectedIndex].MonikerString);

            _finalVideo.NewFrame += (s, a) =>
            
                try
                
                    System.Drawing.Image img = (Bitmap)a.Frame.Clone();
                    var ms = new MemoryStream();
                    img.Save(ms, ImageFormat.Bmp);
                    ms.Seek(0, SeekOrigin.Begin);
                    var bitmapImage = new BitmapImage();
                    bitmapImage.BeginInit();
                    bitmapImage.StreamSource = ms;
                    bitmapImage.EndInit();
                    bitmapImage.Freeze();
                    Dispatcher.BeginInvoke(new ThreadStart(() =>
                    
                        CameraStream.Source = bitmapImage;
                        ReadQrCode(bitmapImage);
                    ));
                
                catch
                
                    //exc
                
            ;

            _finalVideo.Start();
        

我如何用MVVM 解决这个问题?

【问题讨论】:

是什么让您认为在视图中隐藏代码是不好的?如果它正在做与 UI 相关的工作,那么拥有这样的代码是完全可以的——这就是你正在做的事情。 我通常只是编写一个接口来抽象这些外部输入/输出的东西。因此,您最终会得到一个 ICommand Scan 属性,该属性在执行时会在接口上调用 Task&lt;QrCode&gt; ReadQrCodeFromCameraAsync 方法。在你的单元测试中,你做了这个接口的假实现。 【参考方案1】:

这很简单,只要您掌握了它并知道“用户控件”和视图之间的区别。

第一个声明是,理想情况下,后面的代码对于视图应该是空的。这是真实的。

但是,这不适用于用户控件。用户控件可以并且应该有代码,因为它们需要自我维持并且不将其逻辑提取到某些视图模型类中。

那么用户控件和视图之间有什么区别?是的,它们通常都派生自UserControl,但这不会使视图默认成为用户控件。重要的是,视图是为一个应用程序制作的非常特定的 UI 片段,不太可能在其他应用程序中重用。

例如,应用程序 A 中的 CustomerDetailViewCustomerDetailPage 将不同于应用程序 B 的同一视图,因为应用程序 B 可能对 CustomerDetailView 有不同的要求。

另一端的用户控件可以跨应用程序重复使用,例如DatePickerCalendarControlCameraControl。例如,此控件可用于可能需要相机的多个应用程序中。

这里重要的是,“用户控件”不知道您的应用程序结构,因此没有视图模型、业务/域模型等。如果您想允许 ViewModels 绑定到您的用户控件(ICommand for例如,启动和回调,或将生成的图片绑定到 ViewModel),然后将依赖项属性放入用户控件中。

当您在应用程序中使用此用户控件时,您只需将视图模型绑定到这些依赖属性 (DP),然后您就获得了抽象。

TL;DR: 视图中的代码不好,用户控件中的代码必要

【讨论】:

视图中的代码是完全可以的,只要它与演示相关。您对 Control 与 View 的区别很有用,但不要将其固定到特定的类。

以上是关于关于在MVVM架构下WPF中UserControl的 visibility Binding问题。 UserControl MVVM的主要内容,如果未能解决你的问题,请参考以下文章

如何在 MVVM 中的 UserControl 之间进行通信 - WPF 应用程序

在 UserControl WPF MVVM caliburn 内的 UserControl 之间切换

wpf mvvm使用问题集锦

使用 MVVM 在 MainWindow 上绑定 UserControl 视图模型

WPF MVVM 通过事件将 UserControl 从一个 ObservableCollection 移动到另一个

如何从作为wpf mvvm模式中的窗口打开的视图模型中关闭用户控件?