簡體   English   中英

如何從繼承的用戶控件訪問 viewModel 依賴屬性?

[英]how to access to viewModel dependency properties from inherited user control?

我在演示 WPF 項目中苦苦掙扎。 我必須認識到我有許多使代碼復雜化的約束。

核心元素是繼承自 UserControl 的控件。 我想盡可能保持其代碼隱藏。 另外,我想在 ControlTemplate 中有它的 XAML。 它的 C# 代碼應該在一個專用的 ViewModel 中(這個例子是一個巨大的項目,擁有一個專用的 viewModel 可以幫助將所有的 viewmodel 分組。但無論如何,說這是強制性的)。 最后但並非最不重要的一點是,我想將此控件的 2 個屬性綁定到外部屬性。

這是我的 MainWindow.xaml 文件:

<Window x:Class="ViewModel_defined_in_ControlTemplate.MainWindow"
        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:ViewModel_defined_in_ControlTemplate"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="MyDictionary.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
    <Grid>
        <StackPanel>
            <local:MyUserControl Template="{StaticResource TextBoxTemplate}"
                                 NomPersonne="sg"/>
            <Button Content="Click me!" Command="{Binding ElementName=MyViewModel,Path=ChangeTextBoxContent}" Width="100" HorizontalAlignment="Left"/>
        </StackPanel>
    </Grid>
</Window>

該按鈕只是更改 NomPersonne 依賴屬性的值(見下文)。 MyDictionary.xaml 包含 ControlTemplate:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:ViewModel_defined_in_ControlTemplate">

    <ControlTemplate x:Key="TextBoxTemplate" TargetType="{x:Type local:MyUserControl}">
        <Grid>
            <Grid.DataContext>
                <local:MyViewModel/>
            </Grid.DataContext>
            <TextBox Width="50" HorizontalAlignment="Left" Text="{TemplateBinding NomPersonne}"/>
        </Grid>


    </ControlTemplate>    
</ResourceDictionary>

我不知道將我的依賴屬性放在哪里,以及如何訪問它。 我試圖把它放在 MyUserControl 中:

namespace ViewModel_defined_in_ControlTemplate
{
    public partial class MyUserControl : UserControl
    {



        public string NomPersonne
        {
            get { return (string)GetValue(NomPersonneProperty); }
            set { SetValue(NomPersonneProperty, value); }
        }

        public static readonly DependencyProperty NomPersonneProperty =
            DependencyProperty.Register("NomPersonne", typeof(string), typeof(MyUserControl), new PropertyMetadata(""));

    }
}

現在可以從 MyUserCONtroll 的 XAML 訪問它,但是我不知道如何訪問它以便讓按鈕的命令更改屬性:

namespace ViewModel_defined_in_ControlTemplate
{
    public class MyViewModel : ViewModelBase
    {

        public RelayCommand ChangeTextBoxContent = new RelayCommand(() => 
        { 
            //...
        }, () => true);

    }

}

我寧願在視圖模型中擁有依賴屬性,但在這種情況下,如何在 MainWindow 的 MyUserControl 的 XAML 中訪問?

謝謝你。

您應該將屬性添加到視圖 model,將UserControl目標屬性綁定到該屬性,並更新視圖 model 中的源屬性:

<local:MyUserControl Template="{StaticResource TextBoxTemplate}" 
                     NomPersonne="{Binding Name}"/>

查看 Model:

public class MyViewModel : ViewModelBase
{
    public RelayCommand ChangeTextBoxContent = new RelayCommand(() =>
    {
        Name = "...":
    }, () => true);

    private string _name;

    public string Name
    {
        get { return _name; }
        set { _name = value; OnPropertyChanged(); }
    }

    ...
}

您還應該在 window 而不是在ResourceDictionary中設置DataContext

<Window x:Class="ViewModel_defined_in_ControlTemplate.MainWindow"
    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:ViewModel_defined_in_ControlTemplate"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="MyDictionary.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
    <Window.DataContext>
        <local:MyViewModel/>
    </Window.DataContext>
    <Grid>
        <StackPanel>
            <local:MyUserControl Template="{StaticResource TextBoxTemplate}"
                                 NomPersonne="{Binding Name}"/>
            <Button Content="Click me!" Command="{Binding ChangeTextBoxContent}" Width="100" HorizontalAlignment="Left"/>
        </StackPanel>
    </Grid>
</Window>

ResourceDictionary應該只定義模板:

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:local="clr-namespace:ViewModel_defined_in_ControlTemplate">

        <ControlTemplate x:Key="TextBoxTemplate" TargetType="{x:Type local:MyUserControl}">
            <Grid>
                <TextBox Width="50" HorizontalAlignment="Left" 
                         Text="{TemplateBinding NomPersonne}"/>
            </Grid>
        </ControlTemplate>
    </ResourceDictionary>

給 UserControl 一個 ViewModel 是一個非常糟糕的主意。 您剛剛偶然發現了這種方法的許多問題之一。 無法在 ViewModel 中定義 DependecyProperty,代碼隱藏是唯一的方法。

為了在代碼隱藏和 ViewModel 之間同步數據,您必須在代碼隱藏中訂閱 ViewModel 的 PropertyChanged,並且每次 ViewModel 中的值更改時,更新代碼隱藏中的相應 DependencyProperties。 這也必須反過來。 當 DependencyProperty 更改時,您必須在 ViewModel 中更新它。 實現這一點並非不可能,但它真的很難看(相信我,我已經做到了;再也不會了)。

另一個問題是將 UserControl(在代碼隱藏或 XAML 中)的 DataContext 設置為 ViewModel。 如果直接在 UserControl 上設置它,綁定將不起作用。 解決方法是設置 UserControl 的第一個子項的 DataContext(同樣,不要這樣做)。

帶有 ViewModel 的 UserControl 是一個非常糟糕的主意。 但這並不是說您的代碼隱藏應該包含所有代碼。 您始終可以將執行某些高級邏輯的方法提取到它們單獨的類中。 static 方法可以在任何地方調用,甚至可以在代碼隱藏中調用。

暫無
暫無

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

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