zoukankan      html  css  js  c++  java
  • wpf – 通过MVVM绑定UserControl依赖属性

    我有一个包含UserControl的MainWindow,它们都是用MVVM模式实现的.
    MainWindowVM具有我想要绑定到UserControl1VM中的属性的属性.但这不起作用.

    这里是一些代码(viewmodels使用某种mvvm框架,在ViewModelBase类中实现INotifyPropertyChanged,但希望没问题):

    MainWindow.xaml:

    <Window x:Class="DPandMVVM.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DPandMVVM"
        Title="MainWindow" Height="300" Width="300">
        <Grid>
            <local:UserControl1 TextInControl="{Binding Text}" />
        </Grid>
    </Window>

    CodeBehind MainWindow.xaml.cs:

    using System.Windows;
    namespace DPandMVVM
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                DataContext = new MainWindowVM();
            }
        }
    }

    MainWindow-ViewModel MainWindowVM.cs:

    namespace DPandMVVM
    {
        public class MainWindowVM : ViewModelBase
        {
            private string _text;
            public string Text { get { return _text; } }
    
            public MainWindowVM()
            {
                _text = "Text from MainWindowVM";
            }
        }
    }

    在这里UserControl1.xaml:

    <UserControl x:Class="DPandMVVM.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" 
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300">
        <Grid>
            <TextBlock Text="{Binding TextInTextBlock}" />  
        </Grid>
    </UserControl>

    Codebehind UserControl1.xaml.cs:

    using System.Windows.Controls;    
    namespace DPandMVVM
    {
        /// <summary>
        /// Interaction logic for UserControl1.xaml
        /// </summary>
        public partial class UserControl1 : UserControl
        {
            public UserControl1()
            {
                InitializeComponent();
                DataContext = new UserControl1VM();
            }
        }
    }

    和Viewmodel UserControl1VM.cs:

    using System.Windows;    
    namespace DPandMVVM
    {
        public class UserControl1VM : DependencyObject
        {
            public UserControl1VM()
            {
                TextInControl = "TextfromUserControl1VM";
            }
    
            public string TextInControl
            {
                get { return (string)GetValue(TextInControlProperty); }
                set { SetValue(TextInControlProperty, value); }
            }
    
            public static readonly DependencyProperty TextInControlProperty =
                DependencyProperty.Register("TextInControl", typeof(string), typeof(UserControl1VM));
        }
    }

    使用此星座,无法在MainWindow.xaml中找到DP. 我究竟做错了什么?

     
    首先,如果要从外部绑定它,则需要在UserControl1中声明DependencyProperty TextInControl.

    在UserControl1中移动DP的声明.

    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }
    
        public string TextInControl
        {
            get { return (string)GetValue(TextInControlProperty); }
            set { SetValue(TextInControlProperty, value); }
        }
    
        public static readonly DependencyProperty TextInControlProperty =
            DependencyProperty.Register("TextInControl", typeof(string), 
                                           typeof(UserControl1));
    }

    其次,你将UserControl的DataContext外部设置为UserControl1VM,

    public UserControl1()
        {
            InitializeComponent();
            DataContext = new UserControl1VM(); <-- HERE (Remove this)
        }

    所以WPF绑定引擎在UserControl1VM中寻找属性Text而不是MainWindowVM.删除设置DataContext并将UserControl1的XAML更新为:

    <UserControl x:Class="DPandMVVM.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" 
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300"
                 x:Name="userControl1">
        <Grid>
            <TextBlock Text="{Binding TextInTextBlock, ElementName=userControl1}" />  
        </Grid>
    </UserControl>

    通过在UserControl上设置x:Name,使用ElementName绑定DP.

    UPDATE

    如果您希望UserControl的ViewModel完好无损,则必须更新MainWindow中的绑定.

    显式告诉WPF绑定引擎在MainWindow的DataContext中使用ElementName查找属性,如下所示:

    <local:UserControl1 TextInControl="{Binding DataContext.Text,
                        ElementName=mainWindow}" />

    为此,您需要在窗口根级别设置x:Name =“mainWindow”.

    出处:http://www.voidcn.com/article/p-udpyjbsd-bue.html

    注意: 在使用MVVM框架的时候,如果在vm里获取UserControl的绑定数据,需要使用双向绑定"{Binding PageIndex,Mode=TwoWay}"

    ======================================================================

    另外在提供一个在界面上使用ContentControl控件来绑定UserControl对象的方法。

    界面元素:

        <Window.DataContext>
            <localVM:BarViewModel />
        </Window.DataContext>
    
        <Grid>
            <StackPanel Height="30" Margin="0,300,2,105">
                <ContentControl Content="{Binding StatusBar}"></ContentControl>
            </StackPanel>
        </Grid>

    对应的BarViewModel类:

        public class BarViewMod : INotifyPropertyChanged
        {
            public BarViewMod()
            {
                StatusBar = new View.UserCtrl.StatusBarView();
            }
    
            public object StatusBar { get; set; }
    
            public event PropertyChangedEventHandler PropertyChanged;
            protected void OnPropertyChanged([CallerMemberName]string propertyName = "")
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }

    StatusBarView对于界面元素

    <UserControl x:Class="WpfApp1.View.UserCtrl.StatusBarView"
                 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:WpfApp1.View.UserCtrl"
                 xmlns:uc="clr-namespace:WpfApp1.VM"
                 mc:Ignorable="d" 
                 d:DesignHeight="25" d:DesignWidth="800">
        <UserControl.DataContext>
            <uc:StatusBarViewModel></uc:StatusBarViewModel>
        </UserControl.DataContext>
        <Grid>
    
            <StatusBar x:Name="MyStatusBar">
                <StatusBar.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="100" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="*" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="100" />
                            </Grid.ColumnDefinitions>
                        </Grid>
                    </ItemsPanelTemplate>
                </StatusBar.ItemsPanel>
                <StatusBarItem>
                    <TextBlock Name="lbMsg" Text="{Binding TestMsg}" />
                </StatusBarItem>
                <Separator Grid.Column="1" />
                <StatusBarItem Grid.Column="2">
                    <TextBlock Text="http://www.baidu.com/file.txt" />
                </StatusBarItem>
                <Separator Grid.Column="3" />
                <StatusBarItem Grid.Column="4">
                    <ProgressBar Value="0" Width="90" Height="16" />
                </StatusBarItem>
            </StatusBar>
    
        </Grid>
    </UserControl>

    StatusBarView对应的ViewModel类:

    namespace WpfApp1.VM
    {
        using System.ComponentModel;
        using System.Runtime.CompilerServices;
        using System.Windows;
    
        public class StatusBarViewModel : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected void OnPropertyChanged([CallerMemberName]string propertyName = "")
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
    
            public string TestMsg { get; set; } = "test....";
    
        }
    }

     如果是使用了其他框架的,可以依照框架修改,如下面是使用了IOC框架的,则在主界面的VM中构造函数中创建UserControl对象:

    StatusBar = _serviceProvider.GetRequiredService<UserCtrl.StatusBarViewModel>();

  • 相关阅读:
    第十六天-面向对象02-成员
    第十五天-面向对象01
    第十四天-内置函数
    第十三天-生成器
    第十二天-函数名 迭代器
    第十一天-函数进阶
    第十天-初识函数
    第九天- 文件操作 r w a 文件复制/修改
    objectives-c基本语法。
    今天开始了objective-c的学习!
  • 原文地址:https://www.cnblogs.com/mq0036/p/12356454.html
Copyright © 2011-2022 走看看