Привязка Viewmodel для просмотра - PullRequest
0 голосов
/ 05 февраля 2020

MainWindow.xaml

<Window x:Class="SDT.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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
        mc:Ignorable="d"
        xmlns:viewModels="clr-namespace:SDT.ViewModels"
        Height="500" Width="700" WindowStyle="None" AllowsTransparency="False" ResizeMode="NoResize" Background="#FF2C2C2C"
        TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.FontWeight="SemiBold">

    <Window.DataContext>
        <viewModels:UserViewModel />
    </Window.DataContext>

    <Grid>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="308,90,0,0" TextWrapping="Wrap" Text = "{Binding Login}" VerticalAlignment="Top" Width="120"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="152,200,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
        <Button Content="Submit" Command="{Binding SubmitLoginDataCommand}" HorizontalAlignment="Left" Margin="567,259,0,0" VerticalAlignment="Top" Width="75"/>
    </Grid>
</Window>

Main Windows .cs

public partial class MainWindow : Window
{
    UserViewModel userViewModel = new UserViewModel();
    public MainWindow()
    {
        InitializeComponent();
        DataContext = userViewModel;

    }
}

UserViewmodel

public class UserViewModel : INotifyPropertyChanged
{
    private UserService userService = new UserService();

    public string _firstName;

    public string Login { get; set; }

    public void SubmitLoginData(object loginData)
    {
        userService.CheckUserExist(Login);
    }

    public ICommand SubmitLoginDataCommand => new RelayCommand(SubmitLoginData, param => true);

    public string FirstName
    {
        get { return _firstName; }
        set
        {
            if (_firstName != value)
            {
                _firstName = value;
                OnPropertyChanged("FirstName");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string name)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
}

Привет. Что не так с привязкой FirstName? Текстовое поле ничего не показывает. publi c string FirstName {} - FirstName здесь имеют значение при отладке. Я пытался без Window.DataContext и только с Text = "{Binding FirstName}" , но безуспешно. Привязка логина работает нормально.

Ответы [ 3 ]

1 голос
/ 05 февраля 2020

Давайте проверим вашу привязку! Давайте добавим к вашей форме текстовый блок и свяжем с ним свойство FirstName. Все, что вы вводите в поле Текст , должно отображаться в тексте блок , если привязка работает правильно.

Ваш MainWindow.xaml должен выглядеть примерно так:

<Window x:Class="SDT.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:viewModels="clr-namespace:Junk.cats"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">

<Grid>
    <TextBox HorizontalAlignment="Left" Height="23" Margin="308,90,0,0" TextWrapping="Wrap" Text = "{Binding Login}" VerticalAlignment="Top" Width="120"/>
    <TextBox HorizontalAlignment="Left" Height="23" Margin="152,200,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
    <Button Content="Submit" Command="{Binding SubmitLoginDataCommand}" HorizontalAlignment="Left" Margin="567,259,0,0" VerticalAlignment="Top" Width="75"/>
    <TextBlock HorizontalAlignment="Left" Height="32" Margin="140,247,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="346"> 
       <Run Text="First Name: "/>
       <Run Text="{Binding Path=FirstName}"/>
    </TextBlock>
</Grid>

Я ожидаю, что этот тест будет работать, и вы увидите, что вы нет проблем с вашими свойствами get / set и обновлениями пользовательского интерфейса. Я считаю, что ваша проблема теперь связана с «экземпляром» (копией) UserViewModel.

Давайте представим, что мы работаем с печатным документом. Когда вы используете = new UserService (); задание, вы печатаете бесплатную sh копию нашего документа. Если мы распечатаем новый документ и передадим его в MainWindow.cs (назовем его «Боб»), И , вы затем напечатаете новую копию в своем коде userService (назовем это «Фрэнк») - это два независимых экземпляра / копии документа.

Нам нужно создать этот объект один раз и сказать «Бобу» и «Фрэнку» работать с одной и той же копией объекта. Не волнуйтесь, это проще, чем вы думаете, и вы начнете привыкать к нему по мере использования.

Я собираюсь использовать некоторые поля STATI C, чтобы упростить устранение неполадок - вам не нужно создавать экземпляр stati c для этой работы, но вам нужно чтобы убедиться, что ваш экземпляр общего класса доступен всем, кто в нем нуждается.

Шаг 1 - Создайте новый класс, назовем его «Представления». Шаг 2 - Сделайте класс publi c stati c Шаг 3 - Создайте Publi c stati c userViewModel здесь:

public static class views
{
    public static UserViewModel userViewModel = new UserViewModel();
}

Now - Давайте изменим ваш MainWindow.cs для использования общего экземпляра этого класса:

    public partial class MainWindow : Window
{


    public MainWindow()
    {
        InitializeComponent();
        DataContext = views.userViewModel;

    }
}

Последнее, что вам нужно сделать - заставить вашу внешнюю функцию работать с той же копией userViewModel! У меня нет этого кода от вас, поэтому я притворяюсь, что ваша функция называется «YourFunctioNToChangeTheName», и она находится в вашем классе «UserService»:

    public class UserService
{
   public void YourFunctionToChangeTheName()
    {
        views.userViewModel.FirstName = "FRANK"; 
    }
}

Ключевым моментом здесь является то, что вы не создаете новую «UserViewModel» - вы повторно используете тот же экземпляр , с которым связан MainWindow.cs - так что пользовательский интерфейс теперь получает «уведомление об изменении свойства» сейчас!

Помните, что UserViewModel (класс) сам по себе не является stati c, мы создали его общий / stati c экземпляр, к которому можно получить доступ из любой точки вашей программы. Я предложил этот подход, чтобы вы могли изучить основы экземпляра :)

Удачи!

1 голос
/ 05 февраля 2020

Я хотел опубликовать второй ответ, чтобы сделать предложение, которое, я думаю, вам действительно понравится. Мы можем сделать так, чтобы ваше событие OnPropertyChanged автоматически называло свойство, позволяя вам просто написать «OnPropertyChanged ()» для запуска обновления пользовательского интерфейса.

Для этого мы будем использовать свойство «Имя участника звонящего», которое выполняет то, что вы думаете, предоставляет имя объекта или свойства, которое называется кодом!

Чтобы использовать это, нам нужно добавить оператор использования в начало вашего класса UserViewModel:

using System.Runtime.CompilerServices;

Затем мы изменим ваш Событие OnPropertyChanged для использования «имени члена вызывающего абонента» , если только не указано указанное c имя. Теперь это должно выглядеть следующим образом:

    private void OnPropertyChanged([CallerMemberName] String name = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }

Теперь - мы обновим вашу собственность, чтобы использовать упрощенный метод:

   public string FirstName
{
    get { return _firstName; }
    set
    {
        if (_firstName != value)
        {
            _firstName = value;
            OnPropertyChanged();
        }
    }
}

И наконец - недавно я изучил альтернативный способ получения / набор, который я предпочитаю. То, что вы делаете, совершенно нормально, и менять его не нужно, но я бы посоветовал попробовать, чтобы увидеть, как вам это нравится :)

    public string FirstName
    {
        get => _firstName; 
        set
        {
            if (_firstName == value) return;
            _firstName = value;
            OnPropertyChanged(); 
        }
    }

Причины: я считаю, что быстрее нажать = = вместо! =, меньше скобок. Если имя равно значению, оно просто вернется (выйдет). Если нет, он пропускает это возвращение! Я люблю это!

1 голос
/ 05 февраля 2020

Вам необходимо удалить из MainWindow.xaml эту часть:

<Window.DataContext> <viewModels:UserViewModel /> </Window.DataContext>

Так как у вас есть Дважды DataContext, В xaml и в cs, так что это не знаю откуда взять данные.

...