【问题标题】:WPF MVVM Binding issues/questionsWPF MVVM 绑定问题/疑问
【发布时间】:2018-04-24 15:15:36
【问题描述】:

我正在使用 MVVM 进行我的第一个 C# WPF 项目,但我有几个问题。

第一,我想列出我模型中的一些对象,当我单击其中一个时,屏幕上会显示一个表单(或默认创建的表单)。在我的表单中,绑定不起作用,我找不到原因。

第一个调用表单视图模型的视图模型:

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") 但绑定不起作用。

我尝试只使用一个视图模型和一个用户控件来完成,绑定效果很好,太好了(但正如预期的那样),当我编辑表单时,列表在我提交之前更新。也许有更好的方法在同一页面上显示列表和编辑表单。

第二次,我正在寻找一种简单的方法来管理多对多关系,而无需使用特定视图。 例如:角色有一个列表 parsonsByRole 和人有一个列表 RolesByPerson,我想在人编辑表单中显示角色和添加/删除按钮的完整列表来填充 RolesByPerson。也许有更好的方法。

谢谢!

【问题讨论】:

  • when i'm editing the form, the list is updated before I commit你需要加UpdateSourceTrigger=LostFocus
  • 您在 ZRoleEditUserControl &lt;UserControl.DataContext&gt; &lt;viewModel:ZRoleEditViewModel/&gt; &lt;/UserControl.DataContext&gt; 中使用了一个新实例 ZRoleEditViewModel 这需要绑定到同一个视图模型。当您在视图中声明 DataContext 时,它会为该视图初始化一个新的。尝试将该视图的 DataContext 留空,并在显示时分配它。我看不到您在第一个视图中分配或使用它的位置,我不确定这是否是所有代码,但无论您在哪里传递 EditRole 作为 DataContext

标签: c# wpf mvvm binding


【解决方案1】:

感谢 cmets,我现在对它的工作原理有了更好的了解。

这是我的解决方案:

第一个视图模型:

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 中加载视图而不是视图模型,并更改了我的编辑视图和视图模型的构造函数,以确保不使用默认构造函数。

第二个视图模型:

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>

我删除了资源和数据上下文标签。

其背后的代码:

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

我的主要问题是修复,绑定运行良好。太好了,我想我在创建编辑表单时必须克隆我的对象角色,或者使用 UpdateSourceTrigger=Explicit 和可能的 BindingGroup。

感谢您的帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-11
    • 1970-01-01
    • 1970-01-01
    • 2011-04-07
    • 2010-12-15
    • 2014-06-19
    • 2014-02-26
    相关资源
    最近更新 更多