Caliburn Micro - 如何公开属性,解决用户控件 WPF 中的绑定问题

发布于 2025-01-20 14:30:52 字数 4761 浏览 3 评论 0原文

我正在使用 Caliburn Micro 学习 MVVM。我有两个视图:ShellView(主窗口)和PersonView(UserControl)。 ShellView 正确绑定到 ShellViewModel 没有任何问题,但它似乎没有正确地将用户控件绑定到其关联的 ViewModel。

我有一个在 ShellViewModel 中初始化的属性 MyPerson,它与 ShellView 中控件的 x:Name 相匹配,通过CM 约定它应该将 DataContext 绑定到 PersonViewModel (我从 this SO发布),但事实并非如此。绑定标签显示 CMTestUserControlMVVM.ViewModels.ShellViewModel

我明确地将 DataContext 添加到 UserControl 中的 ViewModel 来解决此问题。

DataContext="CMTestUserControlMVVM.ViewModels.PersonViewModel"

我使用绑定标签验证了它,因为它显示 CMTestUserControlMVVM.ViewModels.PersonViewModel,但我现在遇到以下问题:

  1. ViewModel 中的属性和操作未绑定。初始化的 MyPerson 值不会被反映,按钮 SayMyName 不会执行任何操作。
  2. 这些属性不会暴露在主窗口中。我最终希望将 PersonView 控件的 FirstName 和 LastName 属性绑定到 Shell 视图中的其他控件。

我该如何解决这些问题?以下是相关代码。

ShellView.xaml

<Window x:Class="CMTestUserControlMVVM.Views.ShellView"
    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:local="clr-namespace:CMTestUserControlMVVM.Views"
    mc:Ignorable="d"
    Title="ShellView" Height="450" Width="800"
    >
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>

    <Button Width="100" x:Name="DoSomething" Content="Do Something"/>

    <local:PersonView Grid.Row="1" x:Name="MyPerson" 
                      Width="350" Height="100"
                      />

    <Label Content="{Binding}" Grid.Row="2" />
</Grid> 

关联的ViewModel

namespace CMTestUserControlMVVM.ViewModels
{
    public class ShellViewModel : Screen
    {
        private PersonViewModel model;

        public PersonViewModel MyPerson
        {
            get { return model; }
            set 
            { 
                model = value;
                NotifyOfPropertyChange(() => MyPerson);
            }
        }

        public ShellViewModel()
        {
            MyPerson = new PersonViewModel()
            {
                FirstName = "Shameel",
                LastName = "Mohammed"
            };
        }

        public void DoSomething()
        {
            MessageBox.Show("Doing Something");
        }
    }
}

PersonView.xaml

<UserControl x:Class="CMTestUserControlMVVM.Views.PersonView"
         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:CMTestUserControlMVVM.Views"
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800"
         DataContext="CMTestUserControlMVVM.ViewModels.PersonViewModel"
         >
<Grid >
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <StackPanel Orientation="Horizontal">
        <TextBlock x:Name="FirstName"/>
        <TextBlock x:Name="LastName"/>
    </StackPanel>
    <Button Grid.Row="1" x:Name="SayMyName" Content="Say My Name!"/>
    <Label Grid.Row="2" Content="{Binding}"/>
</Grid>

关联的ViewModel

namespace CMTestUserControlMVVM.ViewModels
{
    public class PersonViewModel : PropertyChangedBase
    {
        private string _firstName;

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

        private string _lastName;

        public string LastName
        {
            get { return _lastName; }
            set 
            { 
                _lastName = value;
                NotifyOfPropertyChange(() => LastName);
            }
        }

        public void SayMyName()
        {
            MessageBox.Show($"Hi {FirstName} {LastName}!");
        }
    }
}

I am learning MVVM using Caliburn Micro. I have two views: ShellView(Main window) and PersonView(UserControl). The ShellView gets bound properly to the ShellViewModel with no problem, but it doesn't seem to properly bind the usercontrol to its associated ViewModel.

I have a property MyPerson initialized in ShellViewModel that matches the x:Name of the control in the ShellView, by CM convention it should bind the DataContext to the PersonViewModel (I got this approach from this SO post), but it doesn't. The Binding label shows CMTestUserControlMVVM.ViewModels.ShellViewModel.

I explicitly added the DataContext to the ViewModel in the UserControl to fix this.

DataContext="CMTestUserControlMVVM.ViewModels.PersonViewModel"

I verified it with the Binding Label as it shows CMTestUserControlMVVM.ViewModels.PersonViewModel, but I have the following issues now:

  1. The properties and Actions in the ViewModel are not bound. The initialized MyPerson's values are not reflected and the button SayMyName doesnt do anything.
  2. The properties are not exposed to the main window. I ultimately want to bind the FirstName and LastName props of PersonView control to other controls in the Shell View.

How do I fix these? Following are the code associated.

ShellView.xaml:

<Window x:Class="CMTestUserControlMVVM.Views.ShellView"
    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:local="clr-namespace:CMTestUserControlMVVM.Views"
    mc:Ignorable="d"
    Title="ShellView" Height="450" Width="800"
    >
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>

    <Button Width="100" x:Name="DoSomething" Content="Do Something"/>

    <local:PersonView Grid.Row="1" x:Name="MyPerson" 
                      Width="350" Height="100"
                      />

    <Label Content="{Binding}" Grid.Row="2" />
</Grid> 

Associated ViewModel:

namespace CMTestUserControlMVVM.ViewModels
{
    public class ShellViewModel : Screen
    {
        private PersonViewModel model;

        public PersonViewModel MyPerson
        {
            get { return model; }
            set 
            { 
                model = value;
                NotifyOfPropertyChange(() => MyPerson);
            }
        }

        public ShellViewModel()
        {
            MyPerson = new PersonViewModel()
            {
                FirstName = "Shameel",
                LastName = "Mohammed"
            };
        }

        public void DoSomething()
        {
            MessageBox.Show("Doing Something");
        }
    }
}

PersonView.xaml:

<UserControl x:Class="CMTestUserControlMVVM.Views.PersonView"
         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:CMTestUserControlMVVM.Views"
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800"
         DataContext="CMTestUserControlMVVM.ViewModels.PersonViewModel"
         >
<Grid >
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <StackPanel Orientation="Horizontal">
        <TextBlock x:Name="FirstName"/>
        <TextBlock x:Name="LastName"/>
    </StackPanel>
    <Button Grid.Row="1" x:Name="SayMyName" Content="Say My Name!"/>
    <Label Grid.Row="2" Content="{Binding}"/>
</Grid>

Associated ViewModel:

namespace CMTestUserControlMVVM.ViewModels
{
    public class PersonViewModel : PropertyChangedBase
    {
        private string _firstName;

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

        private string _lastName;

        public string LastName
        {
            get { return _lastName; }
            set 
            { 
                _lastName = value;
                NotifyOfPropertyChange(() => LastName);
            }
        }

        public void SayMyName()
        {
            MessageBox.Show(
quot;Hi {FirstName} {LastName}!");
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

满栀 2025-01-27 14:30:52
  1. 删除dataContext =“ cmtestusercontrolmvvv.m.viewmodels.personviewmodel”,因为这将dataContext设置为string> string> string字符串毫无意义。 P>

  2. usercontrolcontentControl在shellview.xaml中:

     &lt; contentControl grid.row =“ 1” x:name =“ myperson” 
                    宽度=“ 350”高=“ 100” /&gt;
     
  1. Remove DataContext="CMTestUserControlMVVM.ViewModels.PersonViewModel" as this sets the DataContext to a string literal which makes no sense.

  2. Replace the UserControl with a ContentControl in ShellView.xaml:

    <ContentControl Grid.Row="1" x:Name="MyPerson" 
                    Width="350" Height="100" />
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文