#c# #wpf #mvvm
#c# #wpf #mvvm
Вопрос:
Я хочу выполнить метод для события TextChange и для определенного текста, я хочу что-то сделать и закрыть окно с помощью MVVM
например, в этой части моего кода я хочу закрыть свое окно:
if (text.Equals("12345"))
{
//Exit from window
}
Я знаю, как я могу сделать это с помощью кнопки, используя команду, как у меня есть в коде следующего примера.
Но как я могу передать окно запущенному свойству, которое привязывается к тексту текстового поля?
или есть другой способ закрыть форму?
Я хочу сделать это в ViewModel, а не в исходном коде, чтобы написать свой код как шаблон MVVM, близкий к тому, что я могу
мой код XAML :
<Window x:Class="PulserTesterMultipleHeads.UserControls.TestWindows"
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:PulserTesterMultipleHeads.UserControls"
mc:Ignorable="d"
Name="MainTestWindow"
Title="TestWindows" Height="450" Width="800">
<Grid>
<StackPanel>
<TextBox Text="{Binding Text,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"></TextBox>
<Button Command="{Binding EndTestExit}"
CommandParameter="{Binding ElementName=MainTestWindow}">Exit</Button>
</StackPanel>
</Grid>
</Window>
код, лежащий в основе XAML :
using PulserTesterMultipleHeads.Classes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace PulserTesterMultipleHeads.UserControls
{
/// <summary>
/// Interaction logic for TestWindows.xaml
/// </summary>
public partial class TestWindows : Window
{
public TestWindows()
{
InitializeComponent();
DataContext = new TestWindowsMV();
}
}
}
Просмотр кода модели :
using PulserTester.ViewModel.Base;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace PulserTesterMultipleHeads.Classes
{
public class TestWindowsMV : INotifyPropertyChanged
{
private string text;
public string Text {
get {
return text;
} set {
text = value;
if (text.Equals("12345"))
{
//Exit from window
}
}
}
/// <summary>
/// for the example
/// </summary>
private ICommand _EndTestExit;
public ICommand EndTestExit
{
get
{
if (_EndTestExit == null)
{
_EndTestExit = new GenericRelayCommand<Window>((window) => EndTestExitAction(window));
}
return _EndTestExit;
}
}
private void EndTestExitAction(Window window)
{
window.Close();
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
************************* Редактировать в качестве ответа ****************************
Изменение в представлении модели :
public string Text {
get {
return text;
} set {
text = value;
if (text.Equals("12345"))
{
CloseAction();
}
}
}
Изменения в коде, лежащие в основе:
public TestWindows()
{
InitializeComponent();
DataContext = new TestWindowsMV();
if (((TestWindowsMV)DataContext).CloseAction == null)
((TestWindowsMV)DataContext).CloseAction = new Action(this.Close);
}
Комментарии:
1. В качестве обходного пути вы можете сделать кнопку закрытия невидимой / отключенной по умолчанию и включить ее только тогда, когда текст в текстовом поле соответствует вашему условию. Не забудьте открыть огонь
propertychanged
(в настоящее время в вашейText
собственности его нет).2. Является ли параметр window переменным? Почему бы вам не установить window как свойство в вашей модели представления и просто вызвать
EndTestExitAction(Window window)
из условного в вашем установщике?3. @PavelAnikhouski Я хочу, чтобы эта скрытая кнопка срабатывала автоматически при появлении нужной строки.. это возможно?
4. Нет ничего против использования события TextBox.TextChanged для закрытия вашего окна. С другой стороны, все в MVVM против того, чтобы ссылаться на ваше ПРЕДСТАВЛЕНИЕ в ViewModel. ViewModel должен быть разделен, и он должен работать без представления. Если вы проведете модульное тестирование своей текущей модели представления, оно завершится неудачей.
5. @NawedNabiZada MVVM не означает отделить мою логику от моей точки зрения? У меня есть логин в моей ViewModel и просмотр в окне
Ответ №1:
Это довольно сложно с MVVM, но что вы можете сделать, так это создать событие внутри вашей ViewModel и прикрепить функцию, которая закроет ваше окно в коде позади вашего представления. Тогда вы сможете вызывать свое событие внутри ViewModel всякий раз, когда вам нужно закрыть окно (или сделать что-то еще, что удобнее делать в View, а не в ViewModel)
Ответ №2:
Самый простой способ закрыть представление из ViewModel — использовать прикрепленное свойство
public static class perWindowHelper
{
public static readonly DependencyProperty CloseWindowProperty = DependencyProperty.RegisterAttached(
"CloseWindow",
typeof(bool?),
typeof(perWindowHelper),
new PropertyMetadata(null, OnCloseWindowChanged));
private static void OnCloseWindowChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
{
if (!(target is Window view))
return;
if (view.IsModal())
view.DialogResult = args.NewValue as bool?;
else
view.Close();
}
public static void SetCloseWindow(Window target, bool? value)
{
target.SetValue(CloseWindowProperty, value);
}
public static bool IsModal(this Window window)
{
var fieldInfo = typeof(Window).GetField("_showingAsDialog", BindingFlags.Instance | BindingFlags.NonPublic);
return fieldInfo != null amp;amp; (bool)fieldInfo.GetValue(window);
}
}
который затем можно привязать к соответствующему свойству в вашей ViewModel
<Window
x:Class="...
vhelp:perWindowHelper.CloseWindow="{Binding ViewClosed}">
private bool? _viewClosed;
public bool? ViewClosed
{
get { return _viewClosed; }
set { Set(nameof(ViewClosed), ref _viewClosed, value); }
}
Подробнее о моем недавнем сообщении в блоге.
Ответ №3:
У вас уже есть почти все, что вам нужно. Все, что вам действительно нужно сделать, это вызвать private void EndTestExitAction(Window window)
из вашего установщика и указать window
его значение во время построения:
public string Text {
get {
return text;
} set {
text = value;
if (text.Equals("12345"))
{
EndTestExitAction(window)
}
}
}
где window
— свойство вашей модели представления.
Комментарии:
1. Не MVVM, плохая практика!
2. Как это не в MVVM? Представление задает текст через модель представления, модель представления вызывает внутри себя метод, который воздействует на представление.
3. ViewModel ничего не знает о представлении… Вы должны разделить эти слои. View знает ViiewModel, но ViewModel ничего не знает о представлении
4. Я полагаю, вы правы в этом, перепутали с Presenter. Но все же, как тогда закрыть окно через MVVM? Даже при использовании командного подхода (в настоящее время реализованного с помощью кнопки) модель представления знает и управляет представлением вне привязки.
5. Одна из самых больших ошибок, которые люди совершают, когда речь заходит о MVVM, заключается в том, что они думают, что исходный код недопустим. Вы все равно можете использовать код или события, такие как Button.Click, TextBox.TextChanged, если это логика просмотра. Все, что связано с логикой модели, должно проходить через ViewModel с привязками