【问题标题】:Converting to MVVM: Using a View Model instead of MainWindow.xaml.cs转换为 MVVM:使用视图模型而不是 MainWindow.xaml.cs
【发布时间】:2021-06-04 08:33:12
【问题描述】:

我正在尝试在我的软件中实现 MVVM。

我想要什么:我想要一个 ViewModel.cs (ViewModel) 文件来代替 MainWindow.xaml.cs (MainWindow) 文件(里面应该只有 InitializeComponent())

我做了什么:我将数据从我的 MainWindow 移动到新创建的 ViewModel。

出了什么问题:我在将 MainWindow 的 XAML 文件绑定到 ViewModel 时遇到问题,出现错误

当前上下文中不存在名称“comPortList/donglesView”

我参考了我认为与我的问题相关的以下链接

  1. How do XAML files associate with cs files?
  2. binding property from another cs file with converter WPF

但我一无所获。有什么我想念的吗?如果我没有提供足够的信息,请告知,或者让我知道。

有用的数据

  1. 相关 MainWindow.xaml 代码:底部三行(comPortList、btnPortOpen 和 donglesView)需要处理 ViewModel 中的代码。
<Window x:Class="comPortTesterEX.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:comPortTesterEX"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
        <!-- -->
    
    
    <Grid>
        <ListBox x:Name="comPortList" SelectionMode="Single" Grid.Row="0" Grid.Column="0" />
        <Button x:Name="btnPortOpen" Grid.Row="0" Grid.Column="1" Click="PortOpen_Click" Content ="Open Port"/>
        <TreeView x:Name="donglesView" Grid.Row="1" Grid.RowSpan="3" Grid.Column="0" Grid.ColumnSpan="2">
  1. ViewModel代码:1中最下面的三行代码,这里依赖代码,但是不知道怎么把两者联系起来。
namespace comPortTesterEX
{
    class ViewModel : ObservableObject
    {
        public ObservableCollection<Dongle> dongles;

        DispatcherTimer timer;

        public ViewModel()
        {
            timer = new DispatcherTimer();
            timer.Tick += new EventHandler(checkAndUpdateComPortList);
            timer.Interval = new TimeSpan(0, 0, 1);
            timer.Start();
            dongles = new ObservableCollection<Dongle>();
            Trace.WriteLine("Started");
            donglesView.ItemsSource = dongles;
        }

        private void checkAndUpdateComPortList(object sender, EventArgs e)
        {
            List<String> portNames = new List<String>();
            foreach (string portName in SerialPort.GetPortNames())
            {
                portNames.Add(portName);
            }
            if (SerialPort.GetPortNames().Count() == 0)
            {
                portNames.Clear();
            }
            comPortList.ItemsSource = portNames;
        }
...
        private void PortOpen_Click(object sender, RoutedEventArgs e)
        {
            bool isComPortInList = false;
            //Checks for each highlighted item (limited to one)
            foreach (String name in comPortList.SelectedItems)
            {
                if (dongles.Count() == 0) // If there is nothing in bottom list -> CREATE ONE
                {
                    createDongle(dongles, name, 0);
                }
                else //If there is already a list
                {
                    for (int i = 0; i < dongles.Count(); i++) // Compare highlighted to EVERY ITEM IN LIST
                    {
                        // Check if it already exists in list
                        if (dongles[i].ComPortName == name)
                        {
                            isComPortInList = true;
                        }   // return true if it does
                    }
                    if (isComPortInList == false)
                    {
                        //Added element is last element, not 0th
                        createDongle(dongles, name, dongles.Count - 1);
                    }
                }
            }
        }
    }
}

ObservableObject 编码复制自 Rachel Lim 的 MVVM 页面,链接为 https://rachel53461.wordpress.com/2011/05/08/simplemvvmexample/

【问题讨论】:

    标签: c# wpf xaml mvvm


    【解决方案1】:

    您不能在除 MainWindow 之外的类中访问 donglesView.ItemsSource(技术上您可以,但您不应该这样做)。

    视图模型应该公开公共只读属性,而不是私有的 donglesportNames 字段

    public ObservableCollection<Dongle> Dongles { get; }
        = new ObservableCollection<Dongle>();
    
    public ObservableCollection<string> PortNames { get; }
        = new ObservableCollection<string>();
    

    视图绑定如下:

    <TreeView ItemsSource="{Binding Dongles}" ... />
    <ListBox ItemsSource="{Binding PortNames}" ... />
    

    集合的更新如下所示:

    public void UpdatePortNames()
    {
        PortNames.Clear();
        foreach (string portName in SerialPort.GetPortNames())
        {
            PortNames.Add(portName);
        }
    }
    

    您还必须在 XAML 中将视图模型类的实例分配给 MainWindow 的 DataContext

    <Window.DataContext>
        <local:ViewModel/>
    </Window.DataContext>
    

    或在代码中

    public MainWindow()
    {
        DataContext = new ViewModel();
        InitializeComponent();
    }
    

    【讨论】:

    • 我明白,但是在通过 XAML(逐字)实现 DataContext 时,我遇到了以下错误:XDG0008:名称空间“.....”中不存在名称“ViewModel”尽管所有内容共享相同的命名空间,并且尽管删除了 .vs 文件,但假设它是一个一般性错误,但之前的自我引导尝试解决该问题时也会发生该错误。
    • 我使用了默认的 local 命名空间前缀。您的命名空间可能不同。只需在代码中进行分配即可。
    • 也许您在进行更改后没有构建项目集。 XAML 设计器不是从项目中而是从项目程序集中获取有关类型的信息。启动执行时,如果有变化,项目会自动重建,错误会消失(如果是因为这个原因发生的话)。或者自己“手动”调用“构建项目”。
    【解决方案2】:

    事实证明,您不能完全将 MainWindow.xaml.cs 排除在外,您可以将其影响最小化并减少初始化组件的所有内容,然后将其绑定到 App 之类的其他东西。

    【讨论】:

    • 你说的不对。在许多情况下,甚至可以删除此文件。在极少数情况下允许使用它(通过典型的 WPF 实现)。主要是为了演示一些简单的教程示例。
    • 道歉,但我没有看到相反的证据。您能否提供一些链接,以便我了解它们是如何实现的?
    • 看看你的问题的标题:“使用视图模型而不是 MainWindow.xaml.cs”正是你想要在 MVVM 方法中做的事情。有一个单独的视图模型类,其中一个实例被分配给顶级视图元素的 DataContext,例如主窗口。如果您搜索“wpf mvvm”,您会在互联网上找到很多示例。
    • Один из моих ответов на этом Форуме: stackoverflow.com/questions/67597202/…
    猜你喜欢
    • 1970-01-01
    • 2023-03-27
    • 2018-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 2010-12-07
    相关资源
    最近更新 更多