WPF MVVM Обязательные вопросы / вопросы - PullRequest
0 голосов
/ 24 апреля 2018

Я делаю свой первый C # WPF-проект с MVVM, и у меня есть несколько вопросов.

Во-первых, я хочу перечислить некоторые объекты из моей модели, и когда я нажимаю на один из них, отображается формана экране (или созданная форма по умолчанию).В моей форме привязка не работает, и я не могу найти почему.

1-я модель представления, которая вызывает модель представления формы:

public class ZRoleViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public ZRoleViewModel()
    {
        IRepository<Role> mRole = new Repository<Role>();
        _roles = new ObservableCollection<Role>(mRole.GetAll());

        SelectedRole = new Role();
        SelectedIndex = -1;

        _editRole = new ZRoleEditViewModel();
    }

    private ObservableCollection<Role> _roles;
    private Role _selectedRole;
    private int _selectedIndex;
    private ZRoleEditViewModel _editRole;

    public ObservableCollection<Role> Roles
    {
        get => _roles;
        set
        {
            _roles = value;
            RaisePropertyChanged("Roles");
        }
    }

    public Role SelectedRole
    {
        get => _selectedRole;
        set
        {
            _selectedRole = value;
            RaisePropertyChanged("SelectedRole");
            if (_selectedRole != null && _editRole != null)
            {
                _editRole.Role = _selectedRole;
            }
        }
    }

    public int SelectedIndex
    {
        get => _selectedIndex;
        set
        {
            _selectedIndex = value;
            RaisePropertyChanged("SelectedIndex");
        }
    }

    public ZRoleEditViewModel EditRole { get => _editRole; set => _editRole = value; }
}

Ее xaml:

<UserControl x:Class="WpfPlanAction.View.ZRoleUserControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:WpfPlanAction.View"
         xmlns:viewModel="clr-namespace:WpfPlanAction.ViewModel"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
    <viewModel:ZRoleViewModel/>
</UserControl.DataContext>
<UserControl.Resources>
    <DataTemplate DataType="{x:Type viewModel:ZRoleEditViewModel}">
        <local:ZRoleEditUserControl/>
    </DataTemplate>
</UserControl.Resources>
<Grid>
    <DockPanel Margin="10">
        <StackPanel DockPanel.Dock="Left">
            <TextBlock Text="Rôles" FontWeight="Bold"/>
            <DataGrid ItemsSource="{Binding Roles}"
                  SelectedItem="{Binding SelectedRole}"
                  SelectedIndex="{Binding SelectedIndex}"
                  IsReadOnly="True"
                  SelectionMode="Single"
                  AutoGenerateColumns="False"
                  RowHeaderWidth="0">
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding Libelle}" Header="Libellé"></DataGridTextColumn>
                </DataGrid.Columns>
            </DataGrid>
        </StackPanel>
        <ContentControl Content="{Binding EditRole}"></ContentControl>
    </DockPanel>
</Grid>

Здесь привязка моей DataGrid работает хорошо.Мой ContentControl отображает мой второй UserControl, но когда я выбираю объект, привязка не работает в моей форме.

Здесь вторая модель представления:

    public class ZRoleEditViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public ZRoleEditViewModel()
    {
        _role = new Role();
    }

    private Role _role;

    public Role Role
    {
        get => _role;
        set
        {
            _role = value;
            RaisePropertyChanged("Role");
        }
    }
}

И xaml:

<UserControl
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:WpfPlanAction.View"
         xmlns:viewModel="clr-namespace:WpfPlanAction.ViewModel"
         xmlns:Model="clr-namespace:WpfPlanAction.Model" x:Class="WpfPlanAction.View.ZRoleEditUserControl"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300" Loaded="UserControl_Loaded">
<UserControl.Resources>
    <CollectionViewSource x:Key="roleViewSource" Source="{Binding Role}" d:DesignSource="{d:DesignInstance {x:Type Model:Role}, CreateList=True}"/>
</UserControl.Resources>
<UserControl.DataContext>
    <viewModel:ZRoleEditViewModel/>
</UserControl.DataContext>
<Grid>
    <Grid x:Name="grid1" VerticalAlignment="Top" Margin="10,10,0,0" HorizontalAlignment="Left" DataContext="{StaticResource roleViewSource}" Width="280">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Label VerticalAlignment="Center" Grid.Row="0" Margin="3" HorizontalAlignment="Left" Grid.Column="0" Content="Abrege:"/>
        <TextBox x:Name="abregeTextBox" Width="209" VerticalAlignment="Center" Text="{Binding Abrege, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" Grid.Row="0" Margin="3,4,-85,4" Height="24" HorizontalAlignment="Left" Grid.Column="1"/>
        <Label VerticalAlignment="Center" Grid.Row="1" Margin="3" HorizontalAlignment="Left" Grid.Column="0" Content="Libelle:"/>
        <TextBox x:Name="libelleTextBox" Width="209" VerticalAlignment="Center" Text="{Binding Libelle, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" Grid.Row="1" Margin="3,4,-84,4" Height="24" HorizontalAlignment="Left" Grid.Column="1"/>
    </Grid>
</Grid>

RaisePropertyChanged ("Role") вызывается, но привязка не работает.

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

И во второй раз я ищу простой способ управления отношением многие ко многим без использования определенногоПосмотреть.Например: у Role есть список parsonsByRole, а у Person есть список RolesByPerson. Я подумал, что нужно отобразить полный список кнопок Role и Add / Remove в форме редактирования Person для заполнения RolesByPerson.Может быть, есть лучший способ сделать это.

Спасибо!

1 Ответ

0 голосов
/ 25 апреля 2018

Благодаря комментариям я теперь лучше понимаю, как это работает.

Вот мое решение:

1-й вид-модель:

public class ZRoleViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public ZRoleViewModel()
    {
        IRepository<Role> mRole = new Repository<Role>();
        _roles = new ObservableCollection<Role>(mRole.GetAll());

        SelectedIndex = -1;
        SelectedRole = new Role();

        _editRole = new ZRoleEditViewModel(SelectedRole);
        _editUC = new ZRoleEditUserControl(_editRole);
    }

    private ObservableCollection<Role> _roles;
    private Role _selectedRole;
    private int _selectedIndex;
    private ZRoleEditViewModel _editRole;
    private ZRoleEditUserControl _editUC;

    public ObservableCollection<Role> Roles
    {
        get => _roles;
        set
        {
            _roles = value;
            RaisePropertyChanged("Roles");
        }
    }

    public Role SelectedRole
    {
        get => _selectedRole;
        set
        {
            _selectedRole = value;
            RaisePropertyChanged("SelectedRole");
            if (_selectedRole != null && _editRole != null)
            {
                _editRole.Role = _selectedRole;
            }
        }
    }

    public int SelectedIndex
    {
        get => _selectedIndex;
        set
        {
            _selectedIndex = value;
            RaisePropertyChanged("SelectedIndex");
        }
    }

    public ZRoleEditUserControl EditUC { get => _editUC; }
}

И вид:

<UserControl x:Class="WpfPlanAction.View.ZRoleUserControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:WpfPlanAction.View"
         xmlns:viewModel="clr-namespace:WpfPlanAction.ViewModel"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
    <viewModel:ZRoleViewModel/>
</UserControl.DataContext>
<Grid>
    <DockPanel Margin="10">
        <StackPanel DockPanel.Dock="Left">
            <TextBlock Text="Rôles" FontWeight="Bold"/>
            <DataGrid ItemsSource="{Binding Roles}"
                  SelectedItem="{Binding SelectedRole}"
                  SelectedIndex="{Binding SelectedIndex}"
                  IsReadOnly="True"
                  SelectionMode="Single"
                  AutoGenerateColumns="False"
                  RowHeaderWidth="0">
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding Libelle}" Header="Libellé"></DataGridTextColumn>
                </DataGrid.Columns>
            </DataGrid>
        </StackPanel>
        <ContentControl Content="{Binding EditUC, Mode=OneTime}" />
    </DockPanel>
</Grid>

Я загружаю в ContentControl представление вместо модели представления и меняю конструктор моего представления редактирования и модели представления, чтобы быть уверенным, что не используется конструктор по умолчанию.

2-й вид-модель:

public class ZRoleEditViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public ZRoleEditViewModel(Role currentRole)
    {
        _role = currentRole;
    }

    private Role _role;

    public Role Role
    {
        get => _role;
        set
        {
            _role = value;
            RaisePropertyChanged("Role");
        }
    }
}

Вид:

<UserControl
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:WpfPlanAction.View"
         xmlns:viewModel="clr-namespace:WpfPlanAction.ViewModel"
         xmlns:Model="clr-namespace:WpfPlanAction.Model" x:Class="WpfPlanAction.View.ZRoleEditUserControl"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300" Loaded="UserControl_Loaded">
<Grid>
    <Grid x:Name="grid1" VerticalAlignment="Top" Margin="10,10,0,0" HorizontalAlignment="Left" Width="280">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Label VerticalAlignment="Center" Grid.Row="0" Margin="3" HorizontalAlignment="Left" Grid.Column="0" Content="Abrege:"/>
        <TextBox x:Name="abregeTextBox" Width="209" VerticalAlignment="Center" Text="{Binding Role.Abrege, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" Grid.Row="0" Margin="3,4,-85,4" Height="24" HorizontalAlignment="Left" Grid.Column="1"/>
        <Label VerticalAlignment="Center" Grid.Row="1" Margin="3" HorizontalAlignment="Left" Grid.Column="0" Content="Libelle:"/>
        <TextBox x:Name="libelleTextBox" Width="209" VerticalAlignment="Center" Text="{Binding Role.Libelle, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" Grid.Row="1" Margin="3,4,-84,4" Height="24" HorizontalAlignment="Left" Grid.Column="1"/>
    </Grid>
</Grid>

Я удаляю ресурсы и теги datacontext.

Его код позади:

    public partial class ZRoleEditUserControl : UserControl
{
    public ZRoleEditUserControl(ZRoleEditViewModel context)
    {
        InitializeComponent();
        this.DataContext = context;
    }
}

Моя главная проблема - исправить, привязка работает хорошо. Слишком хорошо, я думаю, мне придется клонировать мой объект Role при создании формы редактирования или использовать UpdateSourceTrigger = Explicit с возможно BindingGroup.

Спасибо за вашу помощь!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...