窗口中的视图模型和用户控件中的视图模型之间的 WPF 数据绑定



我有一个窗口和一个用户控件在这个窗口中使用。

我已经做到了以下几点:

    将窗口属性
  1. 绑定到窗口的视图模型属性。
  2. 将用户控件属性
  3. 绑定到用户控件的视图模型属性。
  4. 将用户控件的属性绑定到窗口的视图模型属性。

在我看来,我认为如果我按特定值设置窗口属性,则用户控件的视图模型的属性将设置为相同的值。

但是用户控件的视图模型的属性未设置为相同的值。

这是整个代码。

MainWindow.xaml.cs

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Window1 w = new Window1();
            w.Mode = RegisterMode.Update;
            w.Show();
        }
    }

窗口1.xaml

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MVVMTest2" x:Name="window" x:Class="MVVMTest2.Window1"
        Title="Window1" Height="300" Width="300">
    <Window.DataContext>
        <local:WindowViewModel></local:WindowViewModel>
    </Window.DataContext>
    <Grid>
        <local:UserControl1 x:Name="uc1" HorizontalAlignment="Left" Height="100" Margin="77,116,0,0" VerticalAlignment="Top" Width="100" Mode="{Binding DataContext.Mode, ElementName=window, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
        <Button Content="Button" HorizontalAlignment="Left" Margin="156,43,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
    </Grid>
</Window>

窗口1.xaml.cs

    public partial class Window1 : Window
    {
        public RegisterMode Mode
        {
            get { return (RegisterMode)GetValue(ModeProperty); }
            set { SetValue(ModeProperty, value); }
        }
        // Using a DependencyProperty as the backing store for Mode.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ModeProperty =
            DependencyProperty.Register("Mode", typeof(RegisterMode), typeof(Window1), new PropertyMetadata(RegisterMode.None));
        public Window1()
        {
            InitializeComponent();
            Binding modeBinding = new Binding();
            modeBinding.Source = this.DataContext;
            modeBinding.Path = new PropertyPath("Mode");
            modeBinding.Mode = BindingMode.TwoWay;
            modeBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            this.SetBinding(Window1.ModeProperty, modeBinding);
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show((uc1.DataContext as UCViewModel).Mode.ToString());
        }
    }

窗口视图模型.cs

    public class WindowViewModel : INotifyPropertyChanged
    {
        RegisterMode mode = RegisterMode.None;
        public event PropertyChangedEventHandler PropertyChanged;
        public RegisterMode Mode
        {
            get { return this.mode; }
            set
            {
                this.mode = value;
                RaisePropertyChanged("Mode");
            }
        }
        void RaisePropertyChanged(string propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

用户控制1.xaml

<UserControl x:Class="MVVMTest2.UserControl1"
             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:MVVMTest2"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.DataContext>
        <local:UCViewModel></local:UCViewModel>
    </UserControl.DataContext>
    <Grid>
    </Grid>
</UserControl>

用户控制1.xaml.cs

    public partial class UserControl1 : UserControl
    {

        public RegisterMode Mode
        {
            get { return (RegisterMode)GetValue(ModeProperty); }
            set { SetValue(ModeProperty, value); }
        }
        // Using a DependencyProperty as the backing store for Mode.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ModeProperty =
            DependencyProperty.Register("Mode", typeof(RegisterMode), typeof(UserControl1), new PropertyMetadata(RegisterMode.None));

        public UserControl1()
        {
            InitializeComponent();
            Binding modeBinding = new Binding();
            modeBinding.Source = this.DataContext;
            modeBinding.Path = new PropertyPath("Mode");
            modeBinding.Mode = BindingMode.TwoWay;
            modeBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            this.SetBinding(UserControl1.ModeProperty, modeBinding);
        }
    }

UCViewModel.cs

    public class UCViewModel : INotifyPropertyChanged
    {
        RegisterMode mode = RegisterMode.None;
        public event PropertyChangedEventHandler PropertyChanged;
        public RegisterMode Mode
        {
            get { return this.mode; }
            set
            {
                this.mode = value;
                RaisePropertyChanged("Mode");
            }
        }
        void RaisePropertyChanged(string propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));                
            }
        }
    }

我做错了什么?请让我知道。

尝试使用此解决方案,在ViewModels之间使用组合。

窗口1.xaml

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MVVMTest2" x:Name="window" x:Class="MVVMTest2.Window1"
        Title="Window1" Height="300" Width="300"
        Mode={Binding UcViewModel.Mode}> <!-- Added this binding -->
    <!-- MOVED THIS TO THE CODE-BEHIND
    <Window.DataContext>
        <local:WindowViewModel></local:WindowViewModel>
    </Window.DataContext>
    -->
    <Grid>
        <local:UserControl1 x:Name="uc1" HorizontalAlignment="Left" Height="100" Margin="77,116,0,0" VerticalAlignment="Top" Width="100" 
                            Mode="{Binding UcViewModel.Mode}"/>
        <Button Content="Button" HorizontalAlignment="Left" Margin="156,43,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
    </Grid>
</Window>

窗口1.xaml.cs

public partial class Window1 : Window
{
    public RegisterMode Mode
    {
        get { return (RegisterMode)GetValue(ModeProperty); }
        set { SetValue(ModeProperty, value); }
    }
    // Using a DependencyProperty as the backing store for Mode.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ModeProperty =
        DependencyProperty.Register("Mode", typeof(RegisterMode), typeof(Window1), new PropertyMetadata(RegisterMode.None));
    public Window1()
    {
        InitializeComponent();
        /* THIS IS NOT NEEDED
        Binding modeBinding = new Binding();
        modeBinding.Source = this.DataContext;
        modeBinding.Path = new PropertyPath("Mode");
        modeBinding.Mode = BindingMode.TwoWay;
        modeBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        this.SetBinding(Window1.ModeProperty, modeBinding)
        */
        // Use the following instead:
        this.DataContext = new WindowViewModel();
    }
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        MessageBox.Show((uc1.DataContext as UCViewModel).Mode.ToString());
    }
}

用户控制1.xaml

<UserControl x:Class="MVVMTest2.UserControl1"
             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:MVVMTest2"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
<!-- THIS PART IS NOT NEEDED
     <UserControl.DataContext>
        <local:UCViewModel></local:UCViewModel>
    </UserControl.DataContext>
 -->
    <Grid>
    </Grid>
</UserControl>

用户控制1.xaml.cs

public partial class UserControl1 : UserControl
{
    public RegisterMode Mode
    {
        get { return (RegisterMode)GetValue(ModeProperty); }
        set { SetValue(ModeProperty, value); }
    }
    // Using a DependencyProperty as the backing store for Mode.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ModeProperty =
        DependencyProperty.Register("Mode", typeof(RegisterMode), typeof(UserControl1), new PropertyMetadata(RegisterMode.None));

    public UserControl1()
    {
        InitializeComponent();
        /* THIS IS NOT NEEDED
        Binding modeBinding = new Binding();
        modeBinding.Source = this.DataContext;
        modeBinding.Path = new PropertyPath("Mode");
        modeBinding.Mode = BindingMode.TwoWay;
        modeBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        this.SetBinding(UserControl1.ModeProperty, modeBinding);
        */
    }
}

窗口视图模型.cs

public class WindowViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    /* Remove this:
    RegisterMode mode = RegisterMode.None;
    public RegisterMode Mode
    {
        get { return this.mode; }
        set
        {
            this.mode = value;
            RaisePropertyChanged("Mode");
        }
    }
    */
    // Use composition instead
    UCViewModel _ucViewModel = null;
    public UCViewModel UcViewModel
    {
        get 
        { 
            if (_ucViewModel == null)
            {
                _ucViewModel = new UCViewModel();
            }
            return _ucViewModel; 
        }
    }
    void RaisePropertyChanged(string propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

还有一件事,您可能希望将 ViewModel Mode属性重命名为另一个名称,如 RegMode 。原因是它在绑定期间在 XAML 代码中令人困惑。

由此: {Binding Mode, Mode=TwoWay}或者,这个: {Binding Path=Mode, Mode=TwoWay}对于这个不太令人困惑的问题: {Binding RegMode, Mode=TwoWay}

最新更新