簡體   English   中英

如何在MVVM模式中創建UserControl?

[英]How to create a UserControl in the MVVM pattern?

當前,在一個實際的應用程序開發中,我正在努力使用MVVM模式中的自定義UserControl

在我的應用程序中,有一個DataGrid ,用戶可以在其中選擇一個條目。 DataGridSelectedItem TwoWay DataGrid到ViewModel的設置為DataContext的字段。 當用戶選擇一個條目時,該字段將正確更新(測試)。 在保存DataGridPage中,該字段通過XAML綁定到以MVVM模式設計的自定義UserControlDependencyProperty :它裸露了自己的ViewModel,並將其設置為DataContext 問題在於,即使正確實現了INotifyPropertyChanged接口,當字段更改時UserControlDependencyProperty也不會更新(請參見下一個最小的工作示例中與傳統控件的比較)。

本實施例中由一的Label和剝開ViewModelUserControl作為DataContextUserControl1由消耗MainWindow和結合相比較,一個的Label

文件MainWindow.xaml:

<Window x:Class="UserControlWithinUserControlDataContext.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Local="clr-namespace:UserControlWithinUserControlDataContext"
        Title="MainWindow"
        Height="350" Width="525"
        >

    <StackPanel Orientation="Horizontal"
                >

        <ListBox SelectedItem="{Binding Text, Mode=TwoWay}"
                 x:Name="listbox"
                 Height="150"
                 >
        </ListBox>

        <Local:UserControl1 Text="{Binding Text, Mode=OneWay}"
                            Height="50" Width="150"
                            />

        <Label Content="{Binding Text, Mode=OneWay}"
               />

    </StackPanel>

</Window>

MainWindow.xaml.cs背后的代碼:

 public partial class MainWindow : Window
    {
        public ViewModelWindow view_model_window
        {
            get { return _view_model; }
        }
        private ViewModelWindow _view_model = new ViewModelWindow();

        public MainWindow()
        {
            InitializeComponent();
            DataContext = view_model_window;

            IList<String> list = new List<String>();
            list.Add("A");
            list.Add("B");
            list.Add("C");
            listbox.ItemsSource = list;
        }
    }

MainWindow的ViewModel,文件ViewModelWindow.cs:

public class ViewModelWindow : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public String Text
    {
        get { return text; }
        set
        {
            if (text != value)
            {
                text = value;
                NotifyPropertyChanged("Text");
            }
        }
    }
    private String text = "Bli";
}

文件UserControl1.xaml:

<UserControl x:Class="UserControlWithinUserControlDataContext.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>
        <Label Content="{Binding Text}"
               Background="Magenta"
               HorizontalAlignment="Stretch"
               />
    </Grid>
</UserControl>

代碼隱藏文件UserControl1.xaml.cs:

 public partial class UserControl1 : UserControl
    {
        public ViewModelUserControl view_model_usercontrol
        {
            get { return _view_model; }
        }
        private ViewModelUserControl _view_model = new ViewModelUserControl();

        public String Text
        {
            get { return (String)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(String), typeof(UserControl1),
                new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.AffectsRender,
                        new PropertyChangedCallback(TextPropertyChangedCallback)));

        private static void TextPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            UserControl1 user_control = d as UserControl1;
            if(user_control != null)
            {
                user_control.view_model_usercontrol.Text = user_control.Text;
            }
        }

        public UserControl1()
        {
            InitializeComponent();
            DataContext = view_model_usercontrol;
        }
    }

UserControl1的ViewModel,文件ViewModelUserControl.cs:

public class ViewModelUserControl : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    public String Text
    {
        get { return text; }
        set
        {
            if (text != value)
            {
                text = value;
                NotifyPropertyChanged("Text");
            }
        }
    }
    private String text = "";
}

正如您在執行此代碼時看到的那樣, MainWindowLabel被更新,而UserControl1Label不被更新。

我究竟做錯了什么? 有沒有辦法使它可行?

非常感謝您提供任何線索。

首先,您不需要在UserControl中添加任何內容,只需添加XAML。 刪除所有的UserControl代碼,然后嘗試。

讓我們解釋一下原因:

您在用戶控件xaml中設置的Content =“ {Binding Text}”,它已綁定到ViewModelWindow。 那行得通。 並刪除

  <Local:UserControl1 => Text="{Binding Text, Mode=OneWay}"

好的,但是在其他情況下在用戶控件中定義屬性是正確的嗎?是的,這樣做是正確的:

<UserControl x:Name="UserControlInstance"...>
<Label Content="{Binding Text, ElementName=UserControlInstance}" ...>

在這種情況下,Text是依賴項屬性,而不是datacontext屬性。

嘗試第一個選項,然后第二個僅定義依賴項屬性,在這種情況下,像您一樣綁定依賴項屬性。 還有一個提示,如果依賴項屬性位於可視元素樹中(如您的情況),則無需調用回調。

感謝Juan的回答,這是在MVVM模式中構思UserControl的解決方案:

我將root命名為UserControl1Grid並設置其DataContext

root.DataContext = view_model_usercontrol;

代替:

DataContext = view_model_usercontrol;

一切正常。

美好的結局 :)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM