gpt4 book ai didi

c# - 了解 MVVM - 如何绑定(bind)数据 View ↔ ViewModel + catch Key pressed on view and start function in viewModel

转载 作者:行者123 更新时间:2023-11-30 23:14:21 26 4
gpt4 key购买 nike

我是 C# 新手,创建了一个运行良好的简单应用程序,但我想使用模式 MVVM 学习 C#。所以我正在尝试将我的应用程序迁移到 MVVM,但我感到很困惑

我的目标很简单:

1) 打开后,应用程序会扫描一个文件夹并索引格式中的所有文件“[number] [name]” - 工作正常!

2) 我有一个只有一个文本框的窗口。用户键入一个数字并按 ENTER。此时我有一个 CatalogViewModel,它是一个 File 集合,应该选择由 textBox 中的数字指定的文件并打开它。

问题 1: 在 MVVM 中,我无法将数据从我的 View Main 传递到我的 ViewModel CatalogViewModel(我不确定如果我做对了)

问题 2: 我无法处理 ENTER 键并触发 CatalogViewModel

中的函数

我对 MVVM 有点困惑,无法继续。我知道这很简单。请问如何解决这 2 个问题(请详细说明,我是 C# 及其所有概念的初学者)

更新 1:

尝试了 janonimus 对问题 1 的解决方案,但数据绑定(bind)只是一种方式。VM 的值转到 VIEW,但 VIEW 上的更改不会转到 VM。我用这种方式实现了 INotifyPropertyChanged

using Prism.Mvvm;
...

public class CatalogViewModel: BindableBase
{

private string selectedValue = "100";
public string SelectedValue
{
get { return selectedValue; }
set { SetProperty(ref selectedValue, value); }
}

但是数据绑定(bind)就在路上XAML

<TextBox x:Name="tbSelectedValue" Text="{Binding SelectedValue, Mode=TwoWay}"

更新 2

找到了问题 1 的解决方案。 janonimus 提供的代码仅以一种方式工作,因为 TextBox.Text 的默认行为是在失去焦点时更新,但在我的情况下,它永远不会失去焦点 see this post

下面的代码解决了问题1:

Text="{Binding Path=SelectedValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}

问题 2 可以通过 Pedro Silva 的回答解决

if (e.Key == Key.Enter && tbSelectedValue.Text != String.Empty)
{
vm.OpenSelectedFile();
tbSelectedValue.Text = String.Empty;
}

但我想使用更复杂的方式实现它,使用 ICommand。按照 janonimus 发送的建议,我创建了 BaseCommand 类 Exactly like this但是当我调用函数 OpenSelectedFile

时它会抛出不匹配错误
private BaseCommand<CatalogViewModel> _selectFileCommand;
public ICommand SelectFileCommand
{
get
{
if (_selectFileCommand == null)
{
_selectFileCommand = new BaseCommand<CatalogViewModel>(OpenSelectedFile, true);
}
return _selectFileCommand;
}
}
public void OpenSelectedFile()
{
try
{
OpenFileByNumber(Int32.Parse(SelectedValue));
}
catch (Exception e)
{
MessageBox.Show("Número inválido: \'" + SelectedValue + "\"",
"ERRO", MessageBoxButton.OK, MessageBoxImage.Warning);
}

}

这是我的引用代码...

主.xaml.cs

namespace SLMT.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class Main : Window
{

public Main()
{
InitializeComponent();
DataContext = new CatalogViewModel();
chosenNumber.Focus();
}



// Permite inserir somente números
private void ChosenNumber_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
Regex regex = new Regex("[^ 0-9]+");
e.Handled = regex.IsMatch(e.Text);
}

private void ChosenNumber_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter && chosenNumber.Text != String.Empty)
{
//catalog.OpenFileByNumber(ConvertToInt(numeroEscolhido.Text));
//catalog.OpenSelectedFile(); // Will become someting like this
chosenNumber.Text = String.Empty;

}
}

private int ConvertToInt(string value)
{
try
{
var str = value.Replace(" ", String.Empty);
return Int32.Parse(str);
}
catch (Exception exc)
{
MessageBox.Show("O número: \"" + chosenNumber.Text + "\" é inválido", "ERRO", MessageBoxButton.OK, MessageBoxImage.Error);
chosenNumber.Text = String.Empty;

return 0;
}
}


/// <summary>
/// Controll what wil lhappen if some KEYS are pressed on APP
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void GMain_KeyUp(object sender, KeyEventArgs e)
{

switch (e.Key){

case Key.Escape:
Environment.Exit(0);
break;

case Key.F1:
//wListFiles = new ListFiles(catalog);
//wListFiles.ShowDialog();
//numeroEscolhido.Text = wListFiles.SelectFile();
//numeroEscolhido.SelectAll();
break;
}


}
}
}

ps: 注释行,我是从没有MVVM的版本导入的

主.xaml

<Window x:Name="wMain" x:Class="SLMT.Views.Main"
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:SLMT.Views"
mc:Ignorable="d"
Title="Ministério Tons" Height="364" Width="700" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" WindowStyle="None">
<Grid x:Name="gMain" KeyUp="GMain_KeyUp">
<Image x:Name="imgBackground" HorizontalAlignment="Left" Height="364" VerticalAlignment="Top" Width="700" Source="/SLMT;component/Resources/img/background2.jpg" Opacity="100"/>
<TextBox x:Name="chosenNumber" HorizontalAlignment="Center" Height="34" Margin="500,294,56,36" TextWrapping="Wrap" VerticalAlignment="Center" Width="144" BorderBrush="{x:Null}" Background="{x:Null}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" UndoLimit="50" ForceCursor="True" PreviewTextInput="ChosenNumber_PreviewTextInput" KeyUp="ChosenNumber_KeyUp" BorderThickness="0" FontSize="20" Opacity="0.6" FontWeight="Bold"/>

</Grid>
</Window>

以及 CatalogViewModel.cs 的相关部分

namespace SLMT.ViewModel
{
public class CatalogViewModel: ObservableCollection <File>
{

private int selectedNumber;

/// <summary>
/// Contain the selected number in the View
/// </summary>
public int SelectedNumber
{
get { return selectedNumber; }
set { selectedNumber = value; }
}


// REMOVED CODE TO SCAN AND INDEX THE FILES



public CatalogViewModel() : base()
{
ScanFiles();
ValidateAndAddFiles();
ShowAlerts();
}





public void OpenSelectedFile()
{
OpenFileByNumber(SelectedNumber);
}


/// <summary>
/// Get the file from catalog identified my the number
/// </summary>
/// <param name="number"></param>
/// <returns>File|null</returns>
private File GetFileByNumber(int number)
{
foreach (var file in this)
{
if (file.number == number){
return file;
}
}

return null;
}

private void OpenFileByNumber(int number)
{
var file = GetFileByNumber(number);

if (file == null)
{
MessageBox.Show("Nenhum arquivo encontrado com o número: \'" + number +"\"",
"ARQUIVO NÃO ENCONTRADO", MessageBoxButton.OK, MessageBoxImage.Warning);
} else
{
file.Open();
}
}
}
}

最佳答案

尝试以下操作以访问您在构造函数中创建的 View 模型。

CatalogViewModel vm = new CatalogViewModel();

public Main()
{
InitializeComponent();
DataContext = vm;
chosenNumber.Focus();
}

然后在您的 key 处理程序中,您可以这样做:

private void ChosenNumber_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter && chosenNumber.Text != String.Empty)
{
//catalog.OpenFileByNumber(ConvertToInt(numeroEscolhido.Text));
//catalog.OpenSelectedFile(); // Will become someting like this

vm.OpenSelectedFile();
chosenNumber.Text = String.Empty;
}
}

更新:使用 ICommand

使用您从 here 指向的 BaseCommand 类.我将以下代码添加到 CatalogViewModel 并使其正常工作。您将 BaseCommand 中的类型作为 View 模型,但这应该是命令参数的类型(基于该帖子中的示例)。

private BaseCommand<object> _selectFileCommand;
public ICommand SelectFileCommand
{
get
{
if (_selectFileCommand == null)
{
_selectFileCommand = new BaseCommand<object>((commandParam) => OpenSelectedFile(commandParam),
(commandParam) => CanOpenSelectedFile(commandParam));
}
return _selectFileCommand;
}
}

public void OpenSelectedFile(object commandParam = null)
{
Debug.WriteLine("CatalogViewModel.OpenSelectedFile was called.");
Debug.WriteLine("SelectedValue = " + this.SelectedValue);
}

public bool CanOpenSelectedFile(object commandParam = null)
{
return true;
}

进入 OpenSelectedFile 方法后,您应该能够将它连接到您想要的功能。

关于c# - 了解 MVVM - 如何绑定(bind)数据 View ↔ ViewModel + catch Key pressed on view and start function in viewModel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43127642/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com